microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.24k stars 12.52k forks source link

Algebraic Data Types and Template Literal Types #44071

Closed wesleyolis closed 3 years ago

wesleyolis commented 3 years ago

Bug Report

Template Literal Types | ### Extends

Extends fails when attempting to evaluate literal objects where the key have been re-written suing templates string

type genAlgebraicKind<TObject extends {}, TKindField extends (string & keyof TObject), TSelect extends TObject[TKindField]> = 
{
    [K in string & keyof TObject as `${K}`]: TSelect;
}

interface TypeA {
kind:'204'
fieldsA:string
}

interface TypeB {
kind:'200'
fieldsB:string
}

type UTypes = TypeA | TypeB

type TRewrite = genAlgebraicKind<TypeB, 'kind','200'>

type SelectKind<T> = T extends {kind:'200' } ? T : never
type result = SelectKind<UTypes> // Works as expected

type SelectKind2<T> = T extends TRewrite ? 'Yes' : never

type result2 = SelectKind2<UTypes>
//Expected: TypeB

type SelectKind3<T> = T extends infer UU & {kind:'200' } ? UU: never
type result3 = SelectKind3<UTypes> // Works as expected

type SelectKind4<T> = T extends infer UU & TRewrite ? UU: never
type result4 = SelectKind4<UTypes>
//Expected: TypeB
RyanCavanaugh commented 3 years ago

I don't see any defect being demonstrated here. The computed types each follow from the definitions.

wesleyolis commented 3 years ago

@RyanCavanaugh Well basically when you attempt to use re-written field name in and extends clause it doesn't work. You don't get the expect results, A extends B doesn't work when B fields key names have been mutated.