【发布时间】:2021-12-16 22:32:55
【问题描述】:
背景
我有一个接受 2 个类型参数的接口。第二个参数是可选的,默认为 void。我还有一个实用程序类型 (CommandReturnType),它使用条件类型来防止 void 在未提供第二个类型参数时成为返回类型。
interface Command<IOType, AdditionalOutputType = void> {
execute(input: IOType): CommandReturnType<IOType, AdditionalOutputType>;
}
type CommandReturnType<A, B> = B extends void ? A : A | B;
我创建了一个实用程序类型,它使用infer 返回一个包含 2 种类型参数类型的元组。
type GetCommandParamTypes<T extends Command<unknown, unknown>> =
T extends Command<infer IO, infer A> ?
[IO, A] :
never;
如果我为它提供只有一个类型参数的接口,它会按预期工作 - 它正确返回 void 作为第二个参数。
type type1 = GetCommandParamTypes<Command<string>>; // [string, void]
但是,如果我为它提供一个实现接口的类,该接口只有一个类型参数,它会在两个槽中返回一个具有该类型的元组。
class TypeACommand implements Command<string> {
execute(input: string): string {
return input;
}
}
type type2 = GetCommandParamTypes<TypeACommand>; // [string, string]
尝试的解决方案
与我打算在 SO 上发布的大多数问题一样,当我写出问题时,它有助于澄清实际发生的情况。
我(我想我)现在明白execute 函数的输入类型和返回类型是在检查类时检索的。所以我突然想到我可以使用Exclude<> 从第二种类型中删除任何重复项。
type GetCommandParamTypes<T extends Command<unknown, unknown>> =
T extends Command<infer IO, infer A> ?
[IO, Exclude<A, IO>] :
never;
当为第二个类型参数提供类型时效果很好:
class MixedTypeCommand implements Command<string | number, Function> {
execute(input: string | number): string | number | Function {
// do something with input here...
return something;
}
}
type type3 = GetCommandParamTypes<MixedTypeCommand>; // [string | number, Function] instead of [string | number, string | number | Function]
但是Exclude<type type> 在类型参数匹配时返回never。
type type4 = GetCommandParamTypes<TypeACommand>; // [string, never]
所以我想出了一个不那么狡猾的计划,将never 替换为void。失败了。
type ReplaceNever<T> = T extends never ? void : T;
type GetCommandParamTypes<T extends Command<unknown, unknown>> =
T extends Command<infer IO, infer A> ?
[IO, ReplaceNever<Exclude<A, IO>>] :
never;
type type5 = GetCommandParamTypes<TypeACommand>; // [string, never]
问题
有没有简单的方法可以替换never?
如果没有,是否有其他解决方案可以让我从第二个元组插槽中删除重复类型,如果结果没有,请将其替换为 void?
所以:
type wrong = GetCommandParamTypes<TypeACommand>; // [string, string]
会变成:
type right = GetCommandParamTypes<TypeACommand>; // [string, void]
【问题讨论】:
-
请记住,这里
GetCommandParamTypes<TypeACommand>是从类实例推断的。这意味着 TS 能够推断方法的返回类型。这就是为什么你得到[string, string]而不是[stirng, void] -
@captain-yossarian 感谢您的回复。是的,我提到我理解这是传递类类型时发生的情况。你的意思是类类型而不是实例?
-
TypeACommand是一种类实例。这很棘手,因为typeof ypeACommand是不同的类型
标签: typescript generics typescript-generics