why below code return ["Why?", [true, false]]
?
ts playground link
export type StartsWith<S extends string, SearchString extends string> = S extends `${SearchString}${infer T}` ? true : false;
export type IsNegative<N extends number> = StartsWith<`${N}`, '-'>;
export type Sub<A extends number, B extends number> = [IsNegative<A>, IsNegative<B>] extends infer R
? R extends [false, false]
? ['Why?', R]
: 'Expected'
: never;
type T0 = [IsNegative<-15>, IsNegative<90>]; // [true, false]
type T1 = Sub<-15, 90>; // ["Why?", [true, false]] /* Why [true, false] extends [false, false] ??? */
CodePudding user response:
It seems that TypeScript is lazily evaluating IsNegative
, or it isn't evaluating it completely...? If we expand IsNegative
to its full form:
type Sub<A extends number, B extends number> = [`${A}` extends `${"-"}${infer T}` ? true : false, `${B}` extends `${"-"}${infer T}` ? true : false] extends infer R
Then you will get "Expected".
Also, if you change the definition of IsNegative
to this:
type IsNegative<N extends number> = `${N}` extends `-${number}` ? true : false;
it will also work.
So my takeaway is that TypeScript is being lazy, and "summarizes" IsNegative
to true | false
(basically, boolean
), and then when needed, expands and evaluates the type...? At least, that's what I imagine what TypeScript is doing.
CodePudding user response:
export type Sub<A extends number, B extends number> = IsNegative<A> extends infer IsNA
? IsNegative<B> extends infer IsNB
? [IsNA, IsNB] extends infer R
? R extends [false, false]
? ['UnExpected, Why?', R]
: 'Expected'
: never
: never
: never;
work well
It seems like you can't compute too many things at once, caching the results in two steps avoids this problem.(I'm used to caching the results of some types of evaluations using Something infer Cache ? ... : never
)
That's a solution I can live with for me