why is TypeScript converting string literal union type to string when assigning in object literal?

后端 未结 3 705
一个人的身影
一个人的身影 2020-12-11 10:16

I love string literal union types in TypeScript. I came across a simple case where I was expecting the union type to be retained.

Here is a simple version:



        
3条回答
  •  误落风尘
    2020-12-11 10:25

    That's because let and const are handled differently by TypeScript. Constants are always treated with the "narrower" type - in this case the literals. Variables (and non-readonly object properties) are treated with the "widened" type - string. This is a rule that comes along with literal types.

    Now, while your second assignment may be a constant, the property of that constant is in fact mutable - it's a non-readonly property. If you don't provide a "contextual type", the narrow inference gets lost and you get the wider string type.

    Here you can read more about literal types. I may quote:

    The type inferred for a const variable or readonly property without a type annotation is the type of the initializer as-is.

    The type inferred for a let variable, var variable, parameter, or non-readonly property with an initializer and no type annotation is the widened literal type of the initializer.

    And even more clearly:

    The type inferred for a property in an object literal is the widened literal type of the expression unless the property has a contextual type that includes literal types.

    By the way, if you provide the contextual type for the constant, the type will be passed on to the variable:

    const bar = foo ? 'foo' : 'bar';
    let xyz = bar // xyz will be string
    
    const bar: 'foo' | 'bar' = foo ? 'foo' : 'bar';
    let xyz = bar // xyz will be 'foo' | 'bar'
    

提交回复
热议问题