ps-aux
ps-aux

Reputation: 12176

TypeScript string union type inferences problem in composite types

I have the following code which won't compile with TypeScript compiler 3.7.3

type Fruit = 'apple' | 'banana'

const val = 'apple'

// Works. TS remembers the value of `val`
const fruit: Fruit = val

type Basket = {
    fruit: Fruit
}

const obj = {
    fruit: 'apple' 
}

// Error: Type 'string' is not assignable to type 'Fruit'.
// TS probably discarded that `fruit` property has concrete value and treats it as any `string`.
const structuralBasket: Basket = obj

// This works 
const declaredBasket: Basket = {
    fruit: 'apple'
}

I need the obj to stay as is. What I cannot do and not looking for in the answer:

Is this a limitation of TypeScript compiler?

If so, is there workaround ? Will this be addressed in the future ?

Upvotes: 2

Views: 449

Answers (1)

Maciej Sikora
Maciej Sikora

Reputation: 20162

The problem is that when you just declare obj its gets a wider type then Fruit is, so what you got is {fruit: string}, what is naturally not assignable to its sub-type. You can add as const

const obj = {
    fruit: 'apple' 
} as const

And such construct will be inferred as {fruit: 'apple'}, what is already assignable to Basket being its subtype.

You can also create such objects by value constructors. Consider:

const makeBasket = (fruit: Fruit): Basket => ({fruit})
const obj = makeBasket('apple'); // Basket object

Upvotes: 2

Related Questions