在 TypeScript 中将任意函数参数推断为对象或元组类型
Inferring arbitrary function arguments as object or tuple type in TypeScript
我正在寻找类似这种类型的东西:
type ArgsType<F extends Function> = ...
其中
ArgsType<(n: number, s: string)=>void>
会给我
[number, string]
或
{n: number, s: string}
根据其中一个答案,我创建了这些类型:
type ArgsType<F extends (...x: any[]) => any>
= F extends (...x: infer A) => any ? A : never;
type CtorArgsType<F extends new (...x: any[]) => any>
= F extends new (...x: infer A) => any ? A : never;
interface RepoGroup {
resetAsync?: () => Promise<void>
}
interface RepoGroupOptions<Reset extends "CanReset" | "CannotReset"="CannotReset"> {
reset: Reset extends "CanReset" ? () => Promise<void> : undefined
}
type RepoGroupCtor<Reset extends "CanReset" | "CannotReset"="CannotReset">
= new (...args: any[]) => RepoGroupOptions<Reset>
export function generate<
CanReset extends "CanReset" | "CannotReset"="CannotReset",
T extends RepoGroupCtor<CanReset>=RepoGroupCtor<CanReset>
>(args: T) {
return class implements RepoGroup {
private args: InstanceType<T>
constructor(...config: CtorArgsType<T>) {
this.args = new args(config) as any
}
resetAsync = this.args.reset
}
}
export const Repo = generate(class {
readonly baseUrl: string
constructor(args: { apiBaseUrl: string }) {
this.baseUrl = args.apiBaseUrl
}
reset: undefined
})
let repository = new Repo()
最后一行显示错误,这是应该的。但是,如果我只向 repo 添加一个通用参数,那么:
export const Repo = generate<"CannotReset">(class {...
然后错误就消失了,好像是个bug
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
即proposed to be added to the standard library。
第 2 轮
当您将至少一个类型参数传递给 generate
时,您将关闭对剩余类型参数的推断并使用默认值 (T = RepoGroupCtor<CanReset>
),并且 RepoGroupCtor<CanReset>
接受一个any[]
的剩余参数,因此没有错误。 Partial type argument inference 会给你一个避免这种情况的方法。
您可以使用 Parameters<T>
。它从(至少)3.2
开始可用
用法:
function log(s: string) { console.log(s)}
type LogArg = Parameters<typeof log>[0]; // string
interface Logger {
log(s: string) => void;
}
type LogArg2 = Parameters<Logger['log']>[0]; // string
我正在寻找类似这种类型的东西:
type ArgsType<F extends Function> = ...
其中
ArgsType<(n: number, s: string)=>void>
会给我
[number, string]
或
{n: number, s: string}
根据其中一个答案,我创建了这些类型:
type ArgsType<F extends (...x: any[]) => any>
= F extends (...x: infer A) => any ? A : never;
type CtorArgsType<F extends new (...x: any[]) => any>
= F extends new (...x: infer A) => any ? A : never;
interface RepoGroup {
resetAsync?: () => Promise<void>
}
interface RepoGroupOptions<Reset extends "CanReset" | "CannotReset"="CannotReset"> {
reset: Reset extends "CanReset" ? () => Promise<void> : undefined
}
type RepoGroupCtor<Reset extends "CanReset" | "CannotReset"="CannotReset">
= new (...args: any[]) => RepoGroupOptions<Reset>
export function generate<
CanReset extends "CanReset" | "CannotReset"="CannotReset",
T extends RepoGroupCtor<CanReset>=RepoGroupCtor<CanReset>
>(args: T) {
return class implements RepoGroup {
private args: InstanceType<T>
constructor(...config: CtorArgsType<T>) {
this.args = new args(config) as any
}
resetAsync = this.args.reset
}
}
export const Repo = generate(class {
readonly baseUrl: string
constructor(args: { apiBaseUrl: string }) {
this.baseUrl = args.apiBaseUrl
}
reset: undefined
})
let repository = new Repo()
最后一行显示错误,这是应该的。但是,如果我只向 repo 添加一个通用参数,那么:
export const Repo = generate<"CannotReset">(class {...
然后错误就消失了,好像是个bug
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
即proposed to be added to the standard library。
第 2 轮
当您将至少一个类型参数传递给 generate
时,您将关闭对剩余类型参数的推断并使用默认值 (T = RepoGroupCtor<CanReset>
),并且 RepoGroupCtor<CanReset>
接受一个any[]
的剩余参数,因此没有错误。 Partial type argument inference 会给你一个避免这种情况的方法。
您可以使用 Parameters<T>
。它从(至少)3.2
用法:
function log(s: string) { console.log(s)}
type LogArg = Parameters<typeof log>[0]; // string
interface Logger {
log(s: string) => void;
}
type LogArg2 = Parameters<Logger['log']>[0]; // string