【TypeScript】基础类型和高级类型

一、基础类型

  1、布尔值:  let isDone:boolean = false;

  2、数值: let a:number = 6;   可以赋值二进制,八进制,十六进制;

  3、字符串: let name:string = "Tom ";   可以使用模板字符串 `${name}`

  4、任意类型:let some:any = "hello";    

  5、数组:let num:number[] = [1,2,3]; 

       联合类型数组: let  num:(number|string)[] = [1,2,3,"4","5"];

       泛型数组:let num:Array<number> = [1,2,3,4];

  6、元组(Tuple):

       表示一个已知元素数量和类型的数组,各元素的类型不必相同;

       let list:[number,string] = [1,'2'];   // 不能多不能少,类型也不能不一样

  7、枚举(enum):

       enum Coror {Red,Green,Blue}    等价于  enum Coror{Red=0,Green=1,Blue=2}  // 可以手动赋值。最后一个数字决定起始值;

       反向得到他的键值  enum Color {Red=1,Green=2,Blue=4}    Color[2] = 'Green';

  8、void: 表示不是任意类型,一般出现在函数中,用来标记函数没有返回值;

       void类型对应2个值, 一个是undefined,一个null;

  9、null 和 undefined:

       默认情况下null和undefined是所有类型的子类型,null与undefined的区别:https://www.cnblogs.com/vickylinj/p/14494478.html

  10、never类型

never类型表示的是那些永不存在的值的类型。 例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。

never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never

下面是一些返回never类型的函数:

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}

二、高级类型

  1、接口(interface)

interface Article {
    title: string;
    count: number;
    content:string;
    fromSite: string;
}
 
const article: Article = {
    title: '好好学习TypeScript',
    count: 9999,
    content: 'xxx...',
    fromSite: 'baidu.com'
}

   在赋值时,如果任何一个字段没有被赋值或者字段对应的数据类型不对, ts都会提示错误。

1.1非必填(?):

   当某个字段不是必填时,可以声明非必填

interface Article {
    title: stirng;
    count: number;
    content:string;
    fromSite?: string; // 非必填
}
 
// 不会报错
const article: Article = {
    title: '为vue3学点typescript(2), 类型',
    count: 9999,
    content: 'xxx...',
}

1.2  用接口定义函数:

// 声明接口
interface Core {
    (n:number, s:string):[number,string]
}
 
// 声明函数遵循接口定义
const core:Core = (a,b)=>{
    return [a,b];
}

1.3 用接口定义类

// 定义
interface Animal {
    head:number;
    body:number;
    foot:number;
    eat(food:string):void;
    say(word:string):string;
}
 
// implements
class Dog implements Animal{
    head=1;
    body=1;
    foot=1;
    eat(food:string){
        console.log(food);
    }
    say(word:string){
        return word;
    }
}

2、交叉类型(&):

   交叉类型是将多个类型合并为一个类型,表示"并且"的关系,用 &连接多个类型, 常用于对象合并;

interface A {a:number,c:string};
interface B {b:string};
 
const a:A = {a:1,c:'2'};
const b:B = {b:'1'};
const ab:A&B = {...a,...b};
console.log(ab.c) // 2

3、联合类型(|):

   联合类型也是将多个类型合并为一个类型, 表示"或"的关系,用|连接多个类型;

function setWidth(el: HTMLElement, width: string | number) {
    el.style.width = 'number' === typeof width ? `${width}px` : width;
}

涉及到类型保护与区分类型,详情见:https://www.tslang.cn/docs/handbook/advanced-types.html

4、泛型类型:

    用类型变量去描述一个类型(类型范围);

1)泛型类型:
function convert<T>(input:T):T{
    return input;
}
// 定义泛型类型
interface Convert {
    <T>(input:T):T
}
// 验证下
let convert2:Convert = convert // 正确不报错
 
 
2)泛型接口:
interface Goods<T>{
    id:number;
    title: string;
    size: T;
}
let apple:Goods<string> = {id:1,title: '苹果', size: 'large'};
let shoes:Goods<number> = {id:1,title: '苹果', size: 43};

5、类型别名

类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
    if (typeof n === 'string') {
        return n;
    }
    else {
        return n();
    }
}

起别名不会新建一个类型 - 它创建了一个新 名字来引用那个类型。 给原始类型起别名通常没什么用,尽管可以做为文档的一种形式使用。

同接口一样,类型别名也可以是泛型 - 我们可以添加类型参数并且在别名声明的右侧传入:

type Container<T> = { value: T };

我们也可以使用类型别名来在属性里引用自己:

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

与交叉类型一起使用,我们可以创建出一些十分稀奇古怪的类型。

type LinkedList<T> = T & { next: LinkedList<T> };

interface Person {
    name: string;
}

var people: LinkedList<Person>;
var s = people.name;
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;

然而,类型别名不能出现在声明右侧的任何地方。

type Yikes = Array<Yikes>; // error

接口 vs. 类型别名的区别

像我们提到的,类型别名可以像接口一样;然而,仍有一些细微差别。

其一,接口创建了一个新的名字,可以在其它任何地方使用。 类型别名并不创建新名字—比如,错误信息就不会使用别名。 在下面的示例代码里,在编译器中将鼠标悬停在 interfaced上,显示它返回的是 Interface,但悬停在 aliased上时,显示的却是对象字面量类型。

type Alias = { num: number }
interface Interface {
    num: number;
}
declare function aliased(arg: Alias): Alias;
declare function interfaced(arg: Interface): Interface;

另一个重要区别是类型别名不能被 extends和 implements(自己也不能 extends和 implements其它类型)。 因为 软件中的对象应该对于扩展是开放的,但是对于修改是封闭的,你应该尽量去使用接口代替类型别名。

另一方面,如果你无法通过接口来描述一个类型并且需要使用联合类型或元组类型,这时通常会使用类型别名。

参照:https://blog.csdn.net/godsor/article/details/111832329

官网基本类型:https://www.tslang.cn/docs/handbook/basic-types.html

官网高级类型:https://www.tslang.cn/docs/handbook/advanced-types.html

posted @ 2021-03-07 21:03  vickylinj  阅读(306)  评论(0编辑  收藏  举报