从C#到TypeScript - 高级类型

C# vs TypeScript - 高级类型

上一篇讲了基础类型,基本上用基础类型足够开发了,不过如果要更高效的开发,还是要看下高级类型,这篇和C#共同点并不多,只是延用这个主题。

联合类型

可以从字面上进行理解:其实就是多个类型联合在一起,用|符号隔开。 如: string | number, 表示希望这个类型既可以是string,又可以是number。 联合类型的字段只能调用这些类型共同拥有的方法,除非类型推论系统自动判断出真正的类型。

//这里sn就是一个联合类型的字段,由于类型推论推断出sn肯定是string,所以sn可以调用string的所有方法
let sn: string | number = 'string, number';
//这里就推断不出具体的类型,只能调用toString, toValue了
function snFunc(): string | number{
    return 'string, number';
}

联合类型不光是可以联合基本类型,也可以是用户自定义的class, interace等。

交叉类型

|就有&,交叉类型就是用&符号隔开,表示把多个类型合在一起,新类型包含所有类型的功能。 一些语言如Python有mixins功能,用这个就很容易做到,主要是类似多重继承,不过个人不是用喜欢这个,明显违反了单一原则。 下面这段代码就显示了mixins结合两个类的功能,看起来是不是有点不大合理,目前的趋势也是组合优先,用组合同样也可以做到这些。

class Person {

    talk(): string {
        return `一个人`;
    }
}

class Dog {

    bark(): string {
        return '汪汪汪';
    }
}

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let func of Object.getOwnPropertyNames(Object.getPrototypeOf(first))) {
        (<any>result)[func] = (<any>first)[func];
    }
    for (let func of Object.getOwnPropertyNames(Object.getPrototypeOf(second))) {
        (<any>result)[func] = (<any>second)[func];
    }
    return result;
}

let personDog = extend(new Person(), new Dog());
console.info(personDog.talk());
console.info(personDog.bark());

类型转换

C#里常用的类型转换一个是前面圆括号加类型,一个是as。 TypeScript和C#一样,只不是圆括号改成尖括号。

let test: any = '123';
let str1: string = <string>test;
let str2: string = test as string;

类型保护

联合类型返回的是多个类型的其中一个,但是用的时候并不知道是哪个,需要一个一个判断,这显得很麻烦。

function get(): number | string{
    return 'test';
}
let test = get();
var len = test.length; //编译不了,不知道test到底是number还是string
let str = '';

if((<string>test).sub){
    // string
} else {
    // number
}

除了通过是否有string特有的方法来判断是否是string,也可以用类似C#的typeof来得到它的类型,而且重要的是会提供类型保护机制, 即在typeof作用域里会知道这个变量的类型。

function get(): number | string{
    return 'test';
}
let test = get();
if(typeof test === 'string'){
    console.info(test.length); // 这里由于typeof确定了test类型是string,所以作用域内可以直接取length,而不用<string>转一次
}

typeof比较是有限制的,自己创建的类返回的都是object,这时会用到instanceof,并且instanceof同样会提供类型保护机制。 另外还有类型断言可以提供类似的功能,不过不如上面的来得方便。

function get(): number | string{
    return 'test';
}
let test = get();
function isStr(p : number | string): p is string{
    return (<string>p).sub !== 'undefined';
}

if(isStr(test)) {
    console.info(test.length);
} else {
    console.info(test + 1);
}

上面p is string就是断言参数pstring类型,从而在isStr后可以自动得到test的类型,并且在else里也知道是number类型。

这点上比C#来得好,一般C#做法可能是用as操作符转过来,然后判断是否为空,如果类型多操作起来也很复杂。

类型别名

类型别名即可以为现有类型取一个新名字。

type newstring = string;
let str: newstring = 'aaa';
console.info(str.length);

在C#中也可以用using strList = System.Generic.List做个别名,不过还是不一样,C#的是可以实例化的。 TypeScript别名不是新建一个类型,而是现有类型的一个引用。 给现在类型起别名意义不大,倒是可以配合联合类型或交叉类型做成一些可读的或比较新颖的类型。 别名也支持泛型,现在就有一个用别名创建了一个Tree类型,不过也只是别名,不能实例化,只能是看的,这点不如接口实在。

class Chicken{}
class Duck{}
type Fowl = Chicken | Duck;

type Tree<T> = {
    value: T;
    left: Tree<T>;
    right: Tree<T>;
}

字符串字面量类型

TypeScript可以让string成为一个类型,比如let strType = 'string type'。 这个可以用在方法参数中,用来限制参数的输入。

function test(param1: 'test1' | 'test2' | 'test3'){

}
test('test'); // 编译不了,参数只能是test1, test2或test3

可辨识联合

综合上面的字符串字面量类型、联合类型、类型保护、类型别名可以创建一个可辨识联合的模式。 必须要在自定义的多个类中有相同的字段,这个字段用的是字符串字面量类型并且把这些类型联合起来。

interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

interface Circle {
    kind: "circle";
    radius: number;
}

type Shape = Square | Rectangle | Circle;

// 这里就可以用可辨识联合
function area(s: Shape) {
    switch (s.kind) {
        case "square": return s.size * s.size;
        case "rectangle": return s.height * s.width;
        case "circle": return Math.PI * s.radius ** 2;
    }
}

类型推论

TypeScript可以根据赋值或上下文推论出变量的类型,所以有时可以不用明确标明变量或函数返回值的类型。

let x = 123; // 这里能推论出x是number,就不用写成这样: let x: number = 123;

function get(){ 
    return [1, 2, 3];
}
let arr = get(); // 这里也能推论出arr是number[];

function get(){
    return [1, '2', 3];
}
let arr = get(); // 这里能推论出arr是(number | string)[];

不过个人觉得除了一些很明显的let x = 123之类可以不写,其他的最好还是写上类型,增加代码可读性。

以上就是TypeScript的类型了,比较灵活也比较难,可能要在实际项目中用用就会比较好掌握。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员的碎碎念

Unicode?utf-8?GB2312?

分享一点关于字符编码的来源的知识,是前段时间在廖雪峰老师的python教程里看到的,觉得很通俗易懂,现在复制了过来分享给各位没看过这个教程的朋友们。Unico...

4109
来自专栏C语言C++游戏编程

C语言编程中复杂的循环结构,你被循环晕了吗?

当一段代码需要执行多次时,您可能会遇到这种情况。通常,语句按顺序执行:首先执行函数中的第一个语句,然后执行第二个语句,依此类推。

912
来自专栏大数据架构师专家

python实战系列之python变量

编程语言中为了能够更好的处理数据,都需要使用一些变量。Python 语言的变量可以是各种不同的数据类型,使用变量的时候不需要声明直接使用就可以。

741
来自专栏web前端教室

JS中值的传递方式 | 前端卧谈会第11期

音频请点此进行收听 音频原文: 今天在segmentfault看到一篇文章,是讲JS传值的方式的,觉得很有价值,想和大家分享一下。 都知道JS中有二种值的传递方...

1826
来自专栏GreenLeaves

Jquery dom搜索之siblings()方法

      如果给定一个dom的元素集合的算则其对象,siblings()方法允许我们在dom树中搜索这个元素集合的同胞元素,并匹配这些元素构造一个新的对象,J...

2007
来自专栏坚毅的PHP

【python学习】文本处理之-translate

2011-09-15 看cookbook 看到很神奇的string.translate 函数 可以剔除字符串中你不需要的串,并可做 maketrans映射 ...

3524
来自专栏菩提树下的杨过

字符编码-使用c#研究

微软的那个臭屁的JOEL(就是写《JOEL说软件》的那个牛人)曾说:“每一位软件开发人员必须、绝对要至少具备UNICODE与字符集知识(没有任何例外)”,我也常...

1807
来自专栏Brian

Scala Turtuial-基本语法

概述 Scala是将面向对象思想与函数式编程思想集一身的编程语言,特别是在大数据和流式处理方面的快速发展,基于Scala语言一些重要的开源框架随之发布,比如:S...

2654
来自专栏java一日一条

使用 Java 8 Optional 的正确姿势

我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPoi...

821
来自专栏非著名程序员

鸡蛋问题来了,是先有Class还是先有Object?

周末比较无聊,在浏览论坛的时候,偶然看到一个程序猿提问的问题,他时这样提问的:突然想到一个很菜的问题, 倒底先有Object还是先有Class?所有类都是Obj...

1946

扫码关注云+社区