Typescript: Why Record is not obvious behavior? Bug?

Created on 16 Aug 2017  路  4Comments  路  Source: microsoft/TypeScript

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.

Question

Most helpful comment

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!

All 4 comments

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...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

siddjain picture siddjain  路  3Comments

MartynasZilinskas picture MartynasZilinskas  路  3Comments

blendsdk picture blendsdk  路  3Comments

wmaurer picture wmaurer  路  3Comments

DanielRosenwasser picture DanielRosenwasser  路  3Comments