TypeScript具有相同参数的多种返回类型 [英] TypeScript multiple return types with identical parameters

查看:391
本文介绍了TypeScript具有相同参数的多种返回类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

为了融入TypeScript的精神,我在组件和服务"中编写了完全类型的签名,该签名扩展到了我对angular2表单的自定义验证功能.

我知道我可以重载函数签名,但这要求每种返回类型的参数都不同,因为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) {}

也许最好避免使用可以返回多种类型的函数,但是由于JavaScript的动态特性,这是惯用的.

参考文献

解决方案

好,如果您要使用适当的类型,这是正确的方法:

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

Background

Trying to get into the spirit of TypeScript, I am writing fully typed signatures in my Components and Services, which extends to my custom validation functions for angular2 forms.

I know that I can overload a function signature, but this requires that the parameters are different for each return type because tsc compiles each signature to a separate function:

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

I also know that I can return a single type (like a Promise) which can itself be of multiple sub-types:

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

However, in the context of angular2 custom form validators, a single signature (one parameter of type FormControl) can return two distinct types: an Object with form errors, or null to indicate the control has no errors.

This, obviously, does not work:

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

Nor do

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

(Interestingly, I get the following errors, rather than something more informative:

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

)

TL;DR

Am I left simply using

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

which would seem to negate the advantage of having type signatures?

More generally, looking forward to ES6

While this question is inspired by angular2 forms validators, which are handled directly by the framework, so you might not care about declaring the return type, it is still generally-applicable, especially given ES6 constructs like function (a, b, ...others) {}

Perhaps it's simply better practice to avoid writing functions that can return multiple types, but it is rather idiomatic, owing to JavaScript's dynamic nature.

References

解决方案

Ok, this is the right way if you want to have proper types:

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 };
}

More general example

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

这篇关于TypeScript具有相同参数的多种返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆