Issue
See the following code:
interface X {
a: string;
b: number;
c: boolean;
}
type A = {
prop: keyof X;
value: X[keyof X];
}
const a: A = { prop: 'a', value: 'a' }; // ok
const b: A = { prop: 'a', value: 1 }; // not ok, value should be string, because X['a'] is string
const c: A = { prop: 'b', value: 1 }; // ok
const d: A = { prop: 'c', value: 1 }; // not ok, value should be boolean, because X['c'] is string
Here I want the type of the .value
property to be string
, if prop
is "a"
, number
for "b"
and boolean
for "c"
, but instead it is string|number|boolean
for all cases, because keyof X
can refer to different keys for each use for type A
. How can I make it refer to the same property twice, without having it explicitly input it into a generic argument of A
?
I feel like I should be using infer
her, but I'm not sure how, and also I might be on the wrong track there.
Solution
I don't believe you can do this without generics. So here it is:
type A<K extends keyof X> = {
prop: K;
value: X[K];
}
The good news is, you only need to specify the generic argument when you're assigning to a variable of an explicitly given type, like so:
const a: A<'a'> = { prop: 'a', value: 'a' };
And it's possible that you will never have this need in your code. For example if you specify a function using this generic type, you will not need to explicitly specify the generic parameter to get it working:
function fn<K extends keyof X>(a: A<K>) {
// something
}
fn({ prop: 'a', value: 'a' }); // ok
fn({ prop: 'a', value: 1 }); // not ok, value should be string, because X['a'] is string
fn({ prop: 'b', value: 1 }); // ok
fn({ prop: 'c', value: 1 }); // not ok, value should be boolean, because X['c'] is string
Answered By - Vojtěch Strnad
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.