I am running into an interesting TypeScript situation here. Let's say I have a long interface like this:
interface Example {
foo: string
bar: number
baz: boolean
abc: string[]
def: number
xyz: boolean
/* ... and more ... */
}
Then, I would want to have a pick-like function to send some of those values forward, like this:
const getRequestValuesToSend = (example: Example) => {
type ExampleKey = keyof Example
const keysToSend: ExampleKey[] = [
'foo',
'bar',
'xyz'
]
const payload = {} as Partial<Example>
keysToSend.forEach((key) => {
payload[key] = example[key] as any /* ???? */
})
return payload
}
I want to know how to get rid of the any
up there.
PS: this was originally already solved by without using any
by using Object.fromEntries
and I am sure I could use a generic Pick implementation from here . Nonetheless, I'm still very curious as how/if this is possible in this current form. Thanks!
I'm not sure there is a way to do what you want. There are some things that can get you part of the way there. For example, you could const
the array and use that to derive a type of the specifics keys.
const keysToSend = [
'foo',
'bar',
'xyz'
] as const;
// 'foo' | 'bar' | 'xyz'
type SelectedKeys = typeof keysToSend[number];
You can then use this to "Pick" from Example and have a better description of the resultant type
const payload = {} as Pick<Example, SelectedKeys>
// The type of payload is
// {
// foo: string,
// bar: number,
// xyz: boolean
// }
This object will correct understand and type usage when the key is known. For example,
// These are type checked and valid
payload['foo'] = example['foo'];
payload['bar'] = example['bar'];
// Below would be an error as the properties are not compatible.
// payload['xyz'] = example['foo'];
// Below would be an error as it is not one of the "selected" keys
// as long as --noImplicitAny or "strict" is true
// payload['baz'] = example['baz'];
In the forEach
, however, key
will correctly be typed as 'foo' | 'bar' | 'xyz'
'foo' | 'bar' | 'xyz'
'foo' | 'bar' | 'xyz'
but this does not help so much. When accessing a property using key
we would know the read type would be either string | number | boolean
string | number | boolean
string | number | boolean
but when writing, we still can't be sure what we are writing to. So while this code is valid,
let a = payload[key]; // string | number | boolean
let b = example[key]; // string | number | boolean
a = b;
The following code is not
payload[key] = example[key];
The compiler is not smart enough to realise that in this case since key is used on the left and right and the types have the same properties so this has to be compatible. Since key
refers to multiple property types, it is not safe to write to. If the SelectedKeys all referred to the same type of property, then this would work.
So in this case I'd be happy to use any
, mark it as an exception and be content that the function provides safety externally. TypeScript is ueful in that we can 'cheat' in exceptional circumstances to keep the code simple and then wrap in something that is strict, safe and typed well.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.