Home > Mobile >  Inconsistent TypeScript behavior
Inconsistent TypeScript behavior

Time:09-02

Can somebody explain me this case, I have some types and definitions:

    type Registro = {
        id: number;
        registro: string;
        nombre: string;
    };

    const registros: Registro[] = [
        {
            id: 0,
            registro: '4324',
            nombre: 'Ben'
        },
        {
            id: 1,
            registro: '232',
            nombre: 'Jill'
        }
    ];

If I use a literal string 'id', TS compiles fine

    const a = registros[0]['id']; //OK

If I use a constant straight from a literal, TS also compiles fine


    const key1 = 'id';
    const c = registros[0][key1]; //OK

If I use a variable as a key even though it says its a :string , it will give an error


    let key2 = 'id';
    const d = registros[0][key2];
    //Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Registro'.
    //No index signature with a parameter of type 'string' was found on type 'Registro'.ts(7053)

If I use a constant as a key coming from a variable. and also it says its a :string , it will also error

    let key3 = 'id';
    const key4 = key3;
    const e = registros[0][key4];
    //Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Registro'.
    //No index signature with a parameter of type 'string' was found on type 'Registro'.

What is the problem?

Typescript REPL

CodePudding user response:

The compiler cannot be sure that the key declared as let will always be equal to one of the keys, so it considers this variable as a general string. You may fix it by setting the type of the key

type keys = 'id' | 'registro' | 'nombre'

let key2: keys = 'id';
const d = registros[0][key2];

Now the compiler will do its best to warn you if key2 is not a valid key.

CodePudding user response:

In short: When you use const to declare a string variable, the compiler will set the type to be the string itself. When you use let\var, the compiler will set it as string, which is not allowed to be used as an index.

Well, I didn't know the answer by myself, and I found this question very interesting. So after digging a little bit, I found the answer:

When you declare a variable via var or let, you are telling the compiler that there is the chance that this variable will change its contents. In contrast, using const to declare a variable will inform TypeScript that this object will never change. The process of going from an infinite number of potential cases (there is an infinite number of possible string values) to a smaller, finite number of potential case (in helloWorld’s case: 1) is called narrowing.

// We're making a guarantee that this variable
// helloWorld will never change, by using const.
 
// So, TypeScript sets the type to be "Hello World", not string
const helloWorld = "Hello World";
 
// On the other hand, a let can change, and so the compiler declares it a string
let hiWorld = "Hi World";

The source: Literal Narrowing

CodePudding user response:

When you use const it works because the type, in your examples, will be the value itself. In const key1 = 'id';, type of key1 is 'id'.

If you assign the const like const key1: string = 'id'; it won't work, as key1 now is type of string.

  • Related