TypeScript 具有相同参数的多种返回类型

Posted

技术标签:

【中文标题】TypeScript 具有相同参数的多种返回类型【英文标题】:TypeScript multiple return types with identical parameters 【发布时间】:2017-03-07 15:33:00 【问题描述】:

背景

为了融入 TypeScript 的精神,我正在我的组件和服务中编写完全类型化的签名,这扩展到了我对 angular2 表单的自定义验证函数。

我知道I can overload a function signature,但这要求每个返回类型的参数都不同,因为tsc 将每个签名编译为单独的函数:

function pickCard(x: suit: string; card: number; []): number;
function pickCard(x: number): suit: string; card: number; ;
function pickCard(x): any  /*common logic*/ ;

我也知道我可以返回一个类型(如 Promise),它本身可以是多个子类型:

private active(): Promise<void|null>  ... 

但是,在 angular2 自定义表单验证器的上下文中,单个签名(FormControl 类型的一个参数)可以返回两种不同的类型:带有表单错误的 Object,或 null 表示控件没有错误。

这显然行不通:

private lowercaseValidator(c: FormControl): null;
private lowercaseValidator(c: FormControl): Object 
    return /[a-z]/g.test(c.value) ? null :  lowercase: this.validationMessages.lowercase ;

也没有

private lowercaseValidator(c: FormControl): null|Object ...
private lowercaseValidator(c: FormControl): <null|Object> ...

(有趣的是,我收到以下错误,而不是提供更多信息:

error TS1110: Type expected.
error TS1005: ':' expected.
error TS1005: ',' expected.
error TS1128: Declaration or statement expected.

)

TL;DR

我是否只是使用

private lowercaseValidator(c: FormControl): any  ... 

这似乎否定了拥有类型签名的优势?

更一般地说,期待 ES6

虽然这个问题的灵感来自于框架直接处理的 angular2 表单验证器,因此您可能不关心声明返回类型,但它仍然普遍适用,尤其是考虑到像 function (a, b, ...others) 这样的 ES6 构造

也许避免编写可以返回多种类型的函数只是更好的做法,但由于 javascript 的动态特性,它相当地道。

参考文献

TypeScript function overloading Typescript syntax for a function returning observable or multiple type https://github.com/Microsoft/TypeScript/issues/11700 https://github.com/Microsoft/TypeScript/issues/10727(...spread) https://github.com/Microsoft/TypeScript/issues/10571&lt; , , type&gt;

【问题讨论】:

你为什么需要空值?它不是一个单独的类型,Object 可以为 null。 (1) 不要使用Object,而是使用any。 (2) 这个:private lowercaseValidator(c: FormControl): null|Object ... 应该可以工作。 null | Object 似乎适用于the playground @SamiKuhmonen Kickself:我没有考虑到这一点。我想我过度思考了强调它将返回“无”或“某物”这一事实的具体需求。也就是说,问题的中间部分仍然(也许)适用。 这不是我的意思,使用Object 几乎就像使用any,但是:“any 类型是使用现有 JavaScript 的一种强大方式,允许您逐步选择加入和在编译期间选择退出类型检查。您可能希望 Object 扮演类似的角色,就像它在其他语言中一样。但是 Object 类型的变量只允许您为它们分配任何值 - 您不能调用任意方法它们,甚至是真实存在的”(typescriptlang.org/docs/handbook/basic-types.html#any) 【参考方案1】:

好的,如果你想拥有正确的类型,这是正确的方法:

type CustomType =  lowercase: TypeOfTheProperty ;
// Sorry I cannot deduce type of this.validationMessages.lowercase,
// I would have to see the whole class. I guess it's something
// like Array<string> or string, but I'm not Angular guy, just guessing.

private lowercaseValidator(c: FormControl): CustomType | null 
    return /[a-z]/g.test(c.value) ? null :  lowercase: this.validationMessages.lowercase ;

更一般的例子

type CustomType =  lowercase: Array<string> ;

class A 
      private obj: Array<string>;

      constructor() 
            this.obj = Array<string>();
            this.obj.push("apple");
            this.obj.push("bread");
      

      public testMethod(b: boolean): CustomType | null 
            return b ? null :  lowercase: this.obj ;
      


let a = new A();
let customObj: CustomType | null = a.testMethod(false);
// If you're using strictNullChecks, you must write both CustomType and null
// If you're not CustomType is sufficiant

【讨论】:

我在使用返回多种类型的方法时遇到问题。如果我有自己的方法返回 CustomType1,如下所示:mymethod(): CustomType1 return someMethodThatReturnsCustomType1AndNull(); 我得到一个错误。如何解决这个问题? 最好使用interface 而不是type,除非您确实需要使用类型。【参考方案2】:

添加到 Erik 的回复中。在他的第二个示例的最后一行,您可以使用“as”关键字,而不是重新声明类型。

let customObj = a.testMethod(false) as CustomType;

所以基本上,如果你有一个函数有多个返回类型,你可以通过使用“as”关键字来指定应该将哪些类型分配给一个变量。

type Person =  name: string; age: number | string ;

const employees: Person[] = [
   name: "John", age: 42,
   name: "April", age: "N/A" 
];

const canTakeAlcohol = employees.filter(emp => 
  (emp.age as number) > 21;
);

【讨论】:

以上是关于TypeScript 具有相同参数的多种返回类型的主要内容,如果未能解决你的问题,请参考以下文章

typescript:传递一个接受较少参数的函数 - 如何为传递的函数强制执行相同数量的参数

TypeScript:返回与参数相同的类型

具有多种类型的函数声明

TypeScript 入门14.泛型

TypeScript 类方法具有与构造函数相同的重载签名

基于可选函数参数的不同返回类型 - Typescript