简体   繁体   中英

Typescript conditional types as function return type

I have a need to make a function return type as conditional type and below is my code

type MyType = "valueA" | "valueB";
type MyTypeOrNull<T> = T extends "valueA" | "valueB" ? MyType : null;
function getValue<T extends string>(value: T) {
  if(value === "valueA" || value === "valueB") {
    return value as MyTypeOrNull<T>;
  }
  return null;
}

But it comes with below error

Conversion of type 'T' to type 'MyTypeOrNull<T>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'string' is not comparable to type 'MyTypeOrNull<T>'.

question is do I really need to replace

return value as MyTypeOrNull<T>;

to

return value as unknown as MyTypeOrNull<T>;

Your T claims it extends string , but MyTypeOrNull can actually be null too.

If you replace that with string | null string | null instead, it will work fine:

function getValue<T extends (string | null)>(value: T) {
  if(value === "valueA" || value === "valueB") {
    return value as MyTypeOrNull<T>;
  }
  return null;
}

In fact, it would work fine - in terms of TS not complaining about it - even if you just casted it without the value check:

function getValue<T extends (string | null)>(value: T) {
    return value as MyTypeOrNull<T>;
}

TS Playground

I'm not convinced if that's what you actually intended your value or the return type to be, but that's what your code is currently saying.


I believe what you actually tried to accomplish is to force TS compiler to determine the type based on the value of the given param. But that is impossible to do - TS works before compilation, and it cannot guess what's the type of the param, if the actual param value will be given in runtime.

I think you'd get closer to your intended solution by looking into the is keyword, since that's the part of TS that can "pretend" to perform those value checks for you even before runtime, allowing you to get rid of the generally less safe unknown casting:

type MyType = "valueA" | "valueB";
type MyTypeOrNull =  MyType | null;

function isMyTypeOrNull(value: string | null): value is MyTypeOrNull {
  return (value === "valueA" || value === "valueB" || value === null);
}

function getValue<T extends string>(value: T): MyTypeOrNull {
  if (isMyTypeOrNull(value)){
    return value as MyTypeOrNull;
  }
  return null;
}

TS Playground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM