我有一个对象类型,可以具有所需的任何属性,但是其属性之一必须是一个函数(如果已定义)。问题是:我希望此函数类型包括所有其他属性作为其参数。请参阅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也不起作用。
答案 0 :(得分:2)
我无法以您想要的方式来进行类型推断。无论我做什么,T
都无法推断,或者它推断但onFoo
属性的参数不能正确推断。我可能会认为这较少是编译器错误,而更多是设计限制。可能与onFoo
参数没有真正的non-inferential type parameter usage site有关。可能与类型推断算法需要多少passes才能成功有关。我真的不确定。我确实知道,当我像这样与编译器战斗时,我通常会迷路。因此,值得尝试进行一些没有争议的事情。
一种更直接的方法是使用两个函数参数(我看你不想这样做),如:
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
})
);
我不知道这对您来说是否可以接受,但是至少它在编译器中可以更好地发挥作用。
哦,希望能有所帮助。祝你好运!