将泛型参数限制为 Typescript 中的联合类型

Lev*_*lit 0 typescript typescript-generics

Typescript 有没有办法将泛型参数限制为联合类型?为了说明我的意图,下面我假装T extends UnionType将实现这一点:

function doSomethingWithUnion<T extends UnionType>(val: T) {}

doSomethingWithUnion<number | string>(...) // good
doSomethingWithUnion<number>(...) // should result in an error
Run Code Online (Sandbox Code Playgroud)

我在另一个 SO 问题 ( 53953814 ) 中发现,我们可以检查类型是否为联合类型:

type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true

type Foo = IsUnion<string | number> // true
type Bar = IsUnion<string> // false
Run Code Online (Sandbox Code Playgroud)

例如,如果泛型参数不是联合类型,则允许断言函数永远不会返回:

declare function doSomethingWithUnion<T>(val: T): [T] extends [UnionToIntersection<T>] ? never: boolean;

doSomethingWithUnion<number>(2) // never
doSomethingWithUnion<string|number>(2) // => boolean
Run Code Online (Sandbox Code Playgroud)

链接到操场

但是,我还没有找到以类似方式约束类型本身的方法。

kay*_*ya3 5

Typescript 只允许您为泛型类型参数指定上限,而不是下限或任何其他约束。所以看起来它应该是不可能的,起初我认为它必须是。但事实证明这可能的,因为 makeT的上限取决于它T自己。

function test<T extends (IsUnion<T> extends true ? any : never)>(arg: T): T {
  // ...
  return arg;
}

// OK
test<string | number>('foobar');

// Error: Type 'string' does not satisfy the constraint 'never'.
test<string>('foobar');

// Error: Argument of type 'string' is not assignable to parameter of type 'never'.
test('foobar');
Run Code Online (Sandbox Code Playgroud)

我能想到的一个警告是T总是可以never,即使那不是联合。这是不可避免的,因为never扩展了所有内容,因此它扩展了类型变量可能具有的任何上限。但是如果T是,never则该函数只能用类型参数调用never(即它永远不能被调用),所以这在实践中应该不是问题。

如果你需要另一个上限T,你可以写那个而不是any

游乐场链接