TN.
TN.

Reputation: 19770

Conditional types issue in TypeScript

This is a simplified example of a complex code:

type ValueType<T> = [T] extends [string] ? Value<string> : Value<T>;

interface Value<T> {
    set(v: T): void
}

export type Bar<T> = T extends true ? boolean : number

function foo<T>(vt: ValueType<Bar<T>>, v: Bar<T>) {
    vt.set(v); <-- error here
}

The latest TypeScript (v4.1.3) fails on the statement vt.set(v) with:

Argument of type 'Bar' is not assignable to parameter of type 'string & Bar'.

(TypeScript playground link)

Is this behavior documented somewhere or is it a bug?

Upvotes: 0

Views: 151

Answers (1)

basarat
basarat

Reputation: 276239

What is the error

Here is the error you are getting:

Argument of type 'Bar<T>' is not assignable to parameter of type 'string & Bar<T>'. 
  Type 'number | boolean' is not assignable to type 'string & Bar<T>'. Type 'number' is not assignable to type 'string & Bar<T>'. 
    Type 'number' is not assignable to type 'string'. 
       Type 'Bar<T>' is not assignable to type 'string'. Type 'number | boolean' is not assignable to type 'string'. 

So the root cause is Type 'Bar<T>' is not assignable to type 'string'. Type 'number | boolean' is not assignable to type 'string'. and it makes perfect sense to have this error and we explain this below

Explanation

Fact 1:

Based on export type Bar<T> = T extends true ? boolean : number

  • Bar can only be boolean or number

Fact 2:

Based on type ValueType<T> = [T] extends [string] ? Value<string> : Value<T>;

  • Means that ValueType can be Value<string>

Fact 3:

Based on foo<T>(vt: ValueType<Bar<T>>, v: Bar<T>)

  • Using Fact 2, means that means vt.set can take string

Resolution

Based on Fact 1 (can only be boolean or number) and Fact 2 (can take a string) we have the error message from TypeScript: Type 'number | boolean' is not assignable to type 'string'

Upvotes: 1

Related Questions