Home > Net >  Generic function Type 'number' is not assignable to type 'U'
Generic function Type 'number' is not assignable to type 'U'

Time:11-02

I am getting this error, Where as U is number and returning the number too.

Type 'number' is not assignable to type 'U'.
function foo<T extends string, U extends number>(a: T): U {
    return  a; // error in this line
}


foo<string, number>('12')

CodePudding user response:

I believe it worth using overloading here:

type UnsafeNumber = number & { tag?: 'UnsafeNumber' }

type ParseInt<Str extends string> =
  Str extends `${infer Digit extends number}`
  ? Digit
  : UnsafeNumber


function foo<T extends string>(a: T): ParseInt<T>
function foo<T extends string>(a: T) {
  return  a;
}

type Result = ParseInt<'.2'>

const _ = foo('42') // 42
const __ = foo('4.2') // 4.2
const ___ = foo('s03') // UnsafeNumber

Playground

Since TS does not distinguish number and NaN I have provided UnsafeNumber which corresponds to NaN. However, it is still not safe and I would recommend you to use parseItn function

ParseInt utility type

Since TS 4.8, TS is able to infer literal number from stringified number. See docs. It means that TS is able to infer 100 from "100". It means that when you provide "42" as an argument, TS will be able to infer it as a digit 100. If you will provide just a regular string, TS will not be able to do it and false branch in conditional type will be evaluated, or in other words UnsafeType will be returned.

UnsafeType is just a regular number with using of branded type pattern. So TS will be able to distinguish regular number and UnsafeNumber. UnsafeNumber means that TS is not able to infer digit number from string and it might be NaN

If you are interested and type inference and validation you can check my this article about number inference and inference on function arguments in general or this answer

CodePudding user response:

you need to use as keyword to cast the return value type

function foo<T extends string, U extends number>(a: T): U {
    return  a as U;

}

foo<string, number>('12')
  • Related