我有一个对象类型,它可以有任何它想要的属性,但是它的属性之一必须是一个函数(如果定义的话)。问题是:我希望此函数类型包含所有其他属性作为其参数。请参见the playground以更好地理解。
// https://github.com/microsoft/TypeScript/issues/14829#issuecomment-504042546
type NoInfer<T> = [T][T extends any ? 0 : never];
type Indexable = {
[key: string]: any
}
type Events<T extends Indexable = Indexable> = {
onFoo?: (arg: Omit<T, keyof Events>) => void
}
type Foo<T extends Indexable> = T & Events<NoInfer<T>>
declare function test<T extends Indexable>(foo: T & Foo<T>): void
test({
a: 1,
onFoo(arg) {
// "typeof arg" should be "{ a: number }"
}
})
我想这是循环类型的问题,因为this basic example也不起作用。
最佳答案
我不能让类型推断按你想要的方式工作。无论我做什么,要么T
无法推断,要么它推断,但是onFoo
属性的参数不能正确推断。我可能会认为这不是一个编译器错误和更多的设计限制。可能与onFoo
参数没有真正的“AA>”有关。这可能与成功的类型推断算法需要多少个AA>有关。我真的不确定。我知道当我像这样和编译器战斗时,我通常会输。所以,尝试一些不那么有争议的事情可能是值得的。
一个更直接的方法是使用两个函数参数(我看到你不想做),如:
const makeOnFoo = <T>(
foo: T,
onFoo?: (arg: T) => void
): T & { onFoo?: (arg: T) => void } => Object.assign(foo, { onFoo });
这个函数将准确地推断出你想要的方式,我相信,推断出的
arg
将是T
类型。如果您定义了这样的test()
:declare function test<T>(
foo: T & { onFoo?: (arg: Omit<T, "onFoo">) => void }
): void;
您至少可以使用
makeFoo()
来获得所需的推断:test(
makeOnFoo({ a: 1 }, arg => {
console.log(arg.a.toFixed()); // okay
})
);
我不知道你是否能接受,但至少它能更好地与编译器配合。
好吧,希望能有所帮助。祝你好运!
non-inferential type parameter usage site
关于typescript - 从其父对象推断方法类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57842079/