conditional type应该允许使用智能属性,而我已经设法从@jcalz获得了有关此问题previous version的帮助。不幸的是,尽管解决了该问题,我仍然可以获得我想要的类型严格性。下面的最后一行应导致错误:
interface Props<T, S extends boolean = boolean> {
value: T;
isString: S;
submit: S extends true ? (arg: string) => void : (arg: T & {}) => void;
}
interface FalseProps<T> {
value: T;
isString: false;
submit: (arg: T & {}) => void;
}
interface TrueProps<T> {
value: T;
isString: true;
submit: (arg: string) => void;
}
function fancyFunction<T>(props: Props<T>): void
function fancyFunction<T>(props: TrueProps<T> | FalseProps<T>): void {
if (props.isString === true) {
props.submit('return a string');
} else if (props.isString === false) {
props.submit(props.value);
}
}
const args1 = {
value: 2,
isString: true,
submit: (arg: string) => console.log(arg),
};
fancyFunction(args1);
const args2 = {
value: { id: 2 },
isString: false,
submit: (arg: { id: number }) => console.log(arg),
};
fancyFunction(args2);
const args3 = {
value: { id: 2 },
isString: false,
submit: (arg: string) => console.log(arg),
};
fancyFunction(args3);
可以找到here的打字稿代码。
答案 0 :(得分:2)
与您的其他问题一样,fancyFunction()
仅在T
中是通用的,而不是S
中的Props<T, S>
。当您仅使用Props<T>
时,将得到其isString
属性与其submit
属性不相关的类型。它们都只是联合,isString
的类型为false
时,什么也不会阻止submit
成为(arg: string)=>void
。这样您就不会出错。
与其尝试使用多个类型参数来挽救该条件类型的事物,不如将fancyFunction()
的实现签名公开为其调用签名?类型TrueProps<T> | FalseProps<T>
是discriminated union,其中isString
是判别属性,它在函数的调用端和实现端都可以根据您的需要进行操作:
function fancyFunction<T>(props: TrueProps<T> | FalseProps<T>): void {
if (props.isString === true) {
props.submit('return a string');
} else if (props.isString === false) {
props.submit(props.value);
}
}
现在,您会注意到对fancyFunction()
的所有三个调用都出错。这是因为args1
,args2
和args3
都被推断为比您预期的更广泛的类型。文字true
或false
往往会扩大以键入boolean
,因为这通常是人们想要的。 (对于let foo = true;
,大多数人都认为应该允许后面的foo = false;
)。如果要覆盖该变量,并保持args
变量尽可能的窄(因此,将true
推定为类型true
而不是boolean
),则可以采用一种方法(在TS3.4 +中)与const
assertions一起使用:
const args1 = {
value: 2,
isString: true as const, // const assertion
submit: (arg: string) => console.log(arg),
};
fancyFunction(args1); // okay
const args2 = {
value: { id: 2 },
isString: false as const, // const assertion
submit: (arg: { id: number }) => console.log(arg),
};
fancyFunction(args2); // okay
const args3 = {
value: { id: 2 },
isString: false as const, // const assertion
submit: (arg: string) => console.log(arg),
}
fancyFunction(args3); // error!
// Types of property 'submit' are incompatible
这应该对您有用。希望能有所帮助;再次祝你好运!