function record<K extends string, T>(object: Record<K, T>): Record<K, T> {
return;
}
interface IPerson {
name: string;
age: 0;
}
let person1: Record<'name', IPerson>; // person1: {name: IPerson}
let pesros2 = record({name: '', age: 1}); // pesros2: {name: strign|number, age: string|number}
Why in the first case, the output types of the fields specifies the type IPerson, and the second string | number? How the compiler understands that the type T belongs to all the available types? Obviously the same is not specified anywhere... Why not - {name: IPerson, age: IPerson},
let person3: Record<'name' | 'age', IPerson>; // person1: {name: IPerson, age: IPerson}
// why T strign|number?? why not {name: IPerson, age: IPerson}?
function record<K extends string, T>(object: Record<K, T>): Record<K, T> {
return;
}
This is a bug? This is the only source of non-Boolean type inference throughout the TypeScript.
I think you might be confused about what Record<K,T> is. It is not an object of type T, but an object whose property keys are of type K and whose property values are of type T.
The object {name: '', age: 1} is just an IPerson. It is not a Record<'name'|'age',IPerson>. An actual Record<'name'|'age',IPerson> would be an object whose keys name and age, and whose values are IPerson, like: {name: {name: 'a', age:0}, age: {name: 'b', age:1}}.
The object {name: '', age: 1} is, however, a Record<'name'|'age', string|number>, since its keys are of type 'name'|'age' and its values are of type string|number.
Does this clear things up for you?
Does this clear things up for you?
@jcalz No, because you described what is obvious. But this behavior is not clean, with obvious to the output of types. Why type inference, for the function parameter, prints Record <'name' | 'Age', string | Number>?
// K === 'name' | 'age', T !== T[K], T === T === IPerson
function record<K extends string, T>(object: Record<K, T>): Record<K, T> {
return;
}
// K === 'name' | 'age', T !== T[K], T === T === IPerson
let person: Record<'name'|'age', IPerosn>
// Rules for type inference, in both cases, are the same, and the results are different.
// And I'll note again, this behavior is only with the Record. Why?
When you call record({name: '', age: 1}), the compiler is trying to match {name:'', age: 1} to Record<K, T> for some K and T. You have written T === IPerson above your declaration of record(), but that is not possible. You have passed in an IPerson, which is not a Record<K,IPerson> for any K. It is a Record<'name'|'age', string|number>, which is what the compiler infers.
You seem to think that a Record<K,T> is itself a T, but it is not. I don't know if I can explain it further without repeating myself. Rest assured that this is not a bug, but a misunderstanding on your part. Good luck!
Rest assured that this is not a bug, but a misunderstanding on your part. Good luck!
@jcalz I read a thousand articles and help on the .ts, but none of the authors did not say a word about the REPORT ONLY.
Probably, if you understand, then you can not explain...
Most helpful comment
When you call
record({name: '', age: 1}), the compiler is trying to match{name:'', age: 1}toRecord<K, T>for someKandT. You have writtenT === IPersonabove your declaration ofrecord(), but that is not possible. You have passed in anIPerson, which is not aRecord<K,IPerson>for anyK. It is aRecord<'name'|'age', string|number>, which is what the compiler infers.You seem to think that a
Record<K,T>is itself aT, but it is not. I don't know if I can explain it further without repeating myself. Rest assured that this is not a bug, but a misunderstanding on your part. Good luck!