Typescript条件属性未检测到错误的函数参数

时间:2019-06-19 19:54:56

标签: typescript

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的打字稿代码。

1 个答案:

答案 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()的所有三个调用都出错。这是因为args1args2args3都被推断为比您预期的更广泛的类型。文字truefalse往往会扩大以键入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

这应该对您有用。希望能有所帮助;再次祝你好运!

Link to code