Reputation: 6844
I have a simple function that uses the keyof
feature:
interface B {
name: string;
age: number;
}
function test(key: keyof B) {}
const c = {
age: 'age'
}
test(c.age);
The issue with the above code is that typescript throws an error that type string is not assignable to keyof B
.
So what is the point of the keyof
feature if it's not working with object key value? I don't want to add as keyof B
.
Upvotes: 1
Views: 774
Reputation: 249536
The problem is that typescript does not infer by default literal types for object properties (even if they are const
).
You can get around this by using a type assertion to the string literal type:
const c = {
age: 'age' as 'age'
}
test(c.age);
Or of you want to infer string literal types for all properties of an object you can use a function (I use a iffe here but it can be a separate function)
const c = (<V extends string, T extends Record<string, V>>(o: T) => o)({
age: 'age'
});
test(c.age);
Or in 3.4 (not yet released) you can use a as const
assertion on the object:
const c = {
age: 'age'
} as const
test(c.age);
Upvotes: 2
Reputation: 174957
The reason is that TypeScript infers c
to be of type {age: string;}
, and not {age: 'age';}
.
Had it inferred the latter, instead of the former, you wouldn't have been able to change c.age
like so:
const c = { age: 'age' }
c.age = 'somethingElse';
Had you called it with the literal 'age'
directly, it would have worked as advertised.
You can override TypeScript inference with a proper type like so:
const c: {age: 'age'} = {
age: 'age',
};
And that would both make the type error disappear, and enforce that you do not assign anything to c.age
other than the literal string 'age'
.
Upvotes: 2
Reputation: 8295
c.age
will be a string because of the implicit typing (c
will be of type {age:string}
). You can define the type for c.age to be keyof B
. This will also restrict you in assigning other values to the age
property and use them accidentaly.
interface B {
name: string;
age: number;
}
function test(key: keyof B) { }
const c: { age: keyof B } = {
age: 'age'
}
test(c.age);
Upvotes: 2