Typescript 如何根据参数类型推断返回类型

Typescript 如何根据参数类型推断返回类型,typescript,generics,Typescript,Generics,我正试图弄清楚如何键入这个函数,以便在它运行之后的四个“测试”。我一直在尝试函数重载和条件类型的各种组合(我真的不懂),并尝试研究expert(我真的不懂),但我似乎无法理解 export function parse<T = unknown>(value: string | null): T { // Can't figure out what to put here ^ return typeof value === 'string'

我正试图弄清楚如何键入这个函数,以便在它运行之后的四个“测试”。我一直在尝试函数重载和条件类型的各种组合(我真的不懂),并尝试研究
expert
(我真的不懂),但我似乎无法理解

export function parse<T = unknown>(value: string | null): T {
                     // Can't figure out what to put here ^
  return typeof value === 'string' ? JSON.parse(value) : null
}

const a = parse<string>('"test"') // a is string
const b = parse<string>(null)     // b is string, but should be null
const c = parse('"test"')         // c is unknown
const d = parse(null)             // d is unknown, but should be null

const json = window.localStorage.getItem('foobar')
const e = parse<string>(json)     // e is string, but should be string | null

如何键入函数的返回类型,使其既能通过我的四个“测试”,又能允许我传入一个可能是其中之一的值,如上面的示例所示?

您只声明了两个重载:

export function parse<T = unknown>(value: string): T;
export function parse<T = unknown>(value: null): null;
在这里,您可以看到所有3个重载都在运行:

const overloadOne = parse(''); // unknown
const overloadOneTyped = parse<string>(''); // string
const overloadTwo = parse(null); // null
const overloadThree = parse<string>(window.localStorage.getItem('foobar')); // string | null

const json = window.localStorage.getItem('foobar'); // string | null
const value = parse<string>(json); // string | null
const-overloadOne=parse(“”);//未知的
const重载onetyped=parse(“”);//一串
const overloadTwo=parse(null);//无效的
const overloadThree=parse(window.localStorage.getItem('foobar');//字符串|空
const json=window.localStorage.getItem('foobar');//字符串|空
常量值=解析(json);//字符串|空

用我尝试过的内容和我遇到的错误更新了问题。是的,我猜我需要使用条件类型,所以我试着阅读它,但似乎不知道怎么做。仅供参考:
typeof
是一个Javascript操作符,它永远不会返回“unknown”,因为它与TS无关。我知道您可能知道这一点,但在谈论TS类型时不使用它有助于避免混淆。@IngoBürk这是一个很好的观点。为了避免以后给其他人带来混淆,我替换了问题中的
typeof
。噢!这是有道理的,而且完全有效!不过出于好奇,是否可以在没有重载的情况下,使用条件类型来编写相同的内容?我不这么认为,在任何情况下,我都会支持重载,因为它们更具可读性,但也许其他人可以提出一个使用条件类型的解决方案。通常,重载函数可以转换为具有条件类型参数/返回类型的泛型函数。在这种情况下,重载函数已经是泛型函数,需要手动指定类型参数。因此,条件类型版本需要两个泛型类型参数,一个需要指定,另一个需要编译器推断。但是语言中没有“部分类型参数推断”,因此您需要同时指定或推断这两个参数或其他一些解决方法,这使得它比重载解决方案更不吸引人,imo。
export function parse<T = unknown>(value: string): T;
export function parse<T = unknown>(value: null): null;
export function parse<T = unknown>(value: string | null): T | null { ... }
export function parse<T = unknown>(value: string): T;
export function parse<T = unknown>(value: null): null;
export function parse<T = unknown>(value: string | null): T | null;
export function parse<T = unknown>(value: string | null): T | null {
  return typeof value === 'string' ? JSON.parse(value) : null;
}
const overloadOne = parse(''); // unknown
const overloadOneTyped = parse<string>(''); // string
const overloadTwo = parse(null); // null
const overloadThree = parse<string>(window.localStorage.getItem('foobar')); // string | null

const json = window.localStorage.getItem('foobar'); // string | null
const value = parse<string>(json); // string | null