无法为函数参数指定Typescript条件属性

无法为函数参数指定Typescript条件属性,typescript,Typescript,应该考虑智能属性,但在最后一行,以下所有内容都会失败: 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

应该考虑智能属性,但在最后一行,以下所有内容都会失败:

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: FalseProps<T> | TrueProps<T>): void {
  if (props.isString === true) {
    props.submit('submit a string');
  } else if (props.isString === false) {
    props.submit(props.value);
  }
}

const args = {
  value: 2,
  isString: true,
  submit: (arg: string) => console.log(arg),
};

fancyFunction(args);
界面道具{
值:T;
isString:S;
提交:S扩展为true?(arg:string)=>void:(arg:T)=>void;
}
接口假道具{
值:T;
isString:错误;
提交:(arg:T)=>作废;
}
界面道具{
值:T;
isString:对;
提交:(arg:string)=>作废;
}
功能fancyFunction(道具:道具):无效;
函数fancyFunction(道具:假道具|真道具):无效{
if(props.isString==true){
props.submit(“提交字符串”);
}else if(props.isString==false){
提交道具(道具值);
}
}
常量args={
价值:2,
是的,
提交:(arg:string)=>console.log(arg),
};
fancyFunction(args);
我得到的是:

Argument of type '{ value: number; isString: boolean; submit: (arg: string) => void; }' is not assignable to parameter of type 'Props<string, boolean>'.
  Types of property 'value' are incompatible.
    Type 'number' is not assignable to type 'string'.
“{value:number;isString:boolean;submit:(arg:string)=>void;}”类型的
参数不能分配给“Props”类型的参数。
属性“值”的类型不兼容。
类型“number”不可分配给类型“string”。
我使用的是3.5.2版


注意:在收到@jcalz答案后,我用一个后续问题扩展了问题,可以在这里找到:

我认为这里有很多问题

首先,您的条件类型正在被完全急切地解析,因为
fancyFunction()
S
中不是泛型的,所以
S
采用其默认值
boolean
,因此
submit
只是类型
((arg:string)=>void)|((arg:T)=>void)
Props
不再是条件类型。我想这没关系,但它可能不像你想象的那样

fancyFunction
()的调用签名的角度来看

function fancyFunction<T>(props: Props<T>): void;
(旁白:您是否希望
isString
的类型为
true
?默认情况下,TypeScript不会以这种方式工作。如果希望
args
的推断范围更窄,可以使用a)

您正在调用
fancyFunction(args)
。这意味着编译器需要在
Props
给定的
args
中推断类型
T
。您可以在
Props
中看到出现了两个位置
T
。这些都是潜在的推断位点或
T
。也就是说,当编译器查看
args
时,它可能会同时查看
属性和
提交
属性的参数类型,以尝试找出
T

当它查看
submit
方法的参数时,会看到
string
,因此
string
成为
T
的候选。它尝试了,但失败了。布莱奇

您可能已经假设编译器将只使用
value
来推断
T
,并且
submit
中的类型
T
应该是一个“”(可能您没有考虑这些特定术语)。实际上,在TypeScript中并没有这些,但这样一来,人们就不会经常查阅它了。您将
T
更改为
T&{}
在您希望不发生推断的位置:

interface Props<T> {
  value: T;
  isString: boolean;
  submit:  ((arg: string) => void) | ((arg: T & {}) => void); // change here
}
我想这正是你想要的


同样,您可能希望更多地注意使用条件类型和
args
变量的类型所做的工作,以确保您所做的是您想要做的。但是
&{}
技巧至少应该有助于解决泛型类型推理的难题

好的,希望能有帮助。祝你好运


谢谢,现在我了解了函数本身:“'submit a string'”类型的
参数不能分配给'string&T&{}类型的参数。
。我还得到
重载签名必须全部为环境或非环境。
用于重载功能。我遗漏了什么?我不知道,我面前没有你的密码。第一个错误表示,
isSubmit()
仍被视为一个错误,并且尚未缩小范围。你应该使用像
TrueProps | falsprops
这样的有区别的联合类型,而不是
Props
第二个错误表明你已经将
declare
放在了函数的一个重载签名前面,但不是所有重载签名前面。我必须脱机一段时间。您最好发布一个新问题,而不是用后续问题更新旧问题。我已经在回答上面提到的问题时付出了相当大的努力,我不想把这个答案的长度增加一倍。
const args: {
    value: number;
    isString: boolean;
    submit: (arg: string) => void;
}
interface Props<T> {
  value: T;
  isString: boolean;
  submit:  ((arg: string) => void) | ((arg: T & {}) => void); // change here
}
fancyFunction(args); // okay, T inferred as number