TypeScript需要提供通用参数

Kiz*_*zer 11 javascript typescript

我有以下功能:

async function get<U>(url: string): Promise<U> {
    return getUrl<u>(url);
}
Run Code Online (Sandbox Code Playgroud)

但是,可以像这样调用它(U由TS设置为任何):

get('/user-url');
Run Code Online (Sandbox Code Playgroud)

有没有办法定义这个函数,以便它需要显式提供U,如

get<User>('/user-url');
Run Code Online (Sandbox Code Playgroud)

Tit*_*mir 15

没有内置的支持,但是我们可以设计一个场景,其中不传入类型参数将使用默认泛型类型参数和条件类型生成错误.即我们将给出U默认值void.如果默认值是实际值U,那么我们将函数的参数键入为不应该传递的东西,以便得到错误:

async function get<U = void>(url: string & (U extends void ? "You must provide a type parameter" : string)): Promise<U> {
    return null as any;
}

get('/user-url'); // Error Argument of type '"/user-url"' is not assignable to parameter of type '"You must provide a type parameter"'.

class User {}
get<User>('/user-url');
Run Code Online (Sandbox Code Playgroud)

错误消息并不理想,但我认为它会传达消息.

  • 这样做将不允许您实际使用“extends”来设置泛型类型约束 (2认同)

pol*_*bri 6

您可以使用多个类型参数:

function contractType<T = void, U extends T = T>(value: unknown): U {
    return value as U
}

const example1: string = contractType(17) // error
const example2: string = contractType("value") // error
const example3: string = contractType<string>("value") // ok
Run Code Online (Sandbox Code Playgroud)

https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-288902999


小智 6

function createCommand<P extends WhatEver = never>(a: P): P {
    a.whatEverProperty; // a is always instanceof WhatEver. Never is overlooked here.
}
Run Code Online (Sandbox Code Playgroud)

大多数情况下最简单的解决方案是指定never为默认类型参数值。never总是可分配给类型参数,即使你用 WhatEver 扩展它,所以函数体不受影响,但这里的返回值会never影响消费者以任何有意义的方式使用这个函数的能力。

(消费者/调用者在他们尝试使用返回值时会收到错误,但如果您的函数纯粹是为了副作用而被调用,您可能需要考虑@Titian 的回答中概述的方法)

never当您通常不会返回时,您可以使用条件类型来制作返回类型P

function createCommand<P extends WhatEver = never>(a: P): P['whatEverProperty'] {
    // a is always instanceof WhatEver. Never is overlooked here.
    return a.whatEverProperty as P extends WhatEver ?
      ? WhatEver
      : never
}
Run Code Online (Sandbox Code Playgroud)

  • 这并没有解决上下文推理的问题。`const s: string = get("./abc")` 将推断泛型类型 `U = string`。实际问题是用户没有使用泛型参数来键入函数参数。他们实际上应该返回“未知”并在运行时显式进行类型检查或转换。 (2认同)