TypeScript入门基础

本文介绍了TypeScript的基础概念,包括其作为JavaScript超集的优势,如类型系统和社区支持。接着,深入讲解了数据类型、接口、数组的类型(包括泛型)、函数的类型、类型断言和声明文件等核心概念,帮助读者入门TypeScript。
摘要由CSDN通过智能技术生成

基础概念

简介:微软开发、js超集、遵循ES6

优势:

  1. 增加了代码的可读性和可维护性:类型系统、编辑器和IDE支持
  2. 非常包容:类型推论、编译报错、兼容第三方库
  3. 活跃的社区:Google、ES6

缺点:

  1. 学习成本:需理解接口、泛型、类、枚举类型等
  2. 短期增加开发成本,但可以减少维护成本
  3. 构建流程需要一些 工作量
  4. 可能和一些库的结合不是很完美
  5. typescript编译的时候即使报错了,还会生成编译结果(可通过tsconfig.json配置使其编译报错不生成编译结果)

 

入门基础

数据类型

字符串类型:  var myname: string = "xiaohong"

数字类型: var age: number = 12;

布尔类型: var man: boolean = true;

空值: let unusable: void = undefined; 只能赋值为undefined和null

Null:let n:null = null;

Undefined:let u: undefined = undefined; //undefined和null是所有类型的子类型,都可以赋值给其他类型的变量

任意类型: var alias: any = 'xxx' //变量声明未指定类型,可以被识别为任意值类型

(类型推论:声明时没有指定类型,虽然在编译的时候报错,但会根据赋的值推断出类型。如果变量声明时没有赋值则推断成any类型。)

联合类型:let u:string | number //既可以赋值string也可以赋值number

(访问联合类型的属性或方法:不确定到底是哪个类型时,只能访问此联合类型的所有类型里共有的属性或方法。)

 

接口

简介:在面向对象语言中,接口是一个很重要的概念,是对行为的抽象,而具体如何行动需要由类(class)去实现(implement)

TypeScript中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对[对象的形状(shape)]进行描述

interface IPerson {  //建议在接口名称前加I前缀做标识
    name: string;
    age: number;
}
let tom: Person = {  //定义的变量比接口少了或者多了一些属性是不允许的
    name: 'Tom',
    age: 25
};
//赋值的时候,变量的形状必须和接口的形状保持一致


//可选属性,设置的可选属性添不添加都可以,但是不可以添加为定义的属性
interface: IPerson {
    name: string;
    age?: number;  //可选属性
}
let tom: Person = {
    name: 'Tom'    //可以给一个属性
}

//任意属性:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
interface IPerson {
    name: string;
    age?: number;
    [propName: string]: any;
}

//只读属性:对象中的一些字段只能在创建的时候被赋值,那么可以用readonly定义只读属性
//只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

 

数组的类型

表示法:类型 + 方括号,数组不允许出现其他的类型

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

用接口表示数组:(不建议这么做,一般常用来表示类数组)

interface NumberArray {
    [index: number]: number;
}
let fibonacci: NumberArray = [1,1,2,4,5];

类数组:类数组不是数组类型,比如arguments

function sum() {
    let args: {
        [index: number]: number;
        length: number;
        callee: Function;
    } = arguments;
}

any在数组中的应用

let list: any[] = ['zhanghe', 25,{website: 'http://zhanghe.com'}];

 

泛型(概述,后期再详细增加内容)

泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性

多个类型参数

泛型约束

泛型接口

泛型类

泛型参数的默认类型

 

函数的类型

函数声明:

定义方式:

1、函数声明:输入多余(或者少于要求的)参数,是不被允许的

function sum(x:number, y:number):number {
    return x + y;
}

2、函数表达式

let mySum: (x: number, y: number) => number = function(x:number, y:number){
    return x + y;
};

 

用接口定义函数的形状:

interface ISearchFunc {
    (source: string, subString: string): boolean;
}
let mySearch: ISearchFunc;
mySearch = function(source: string, subString: string){
    return source.search(subString) !== -1;
}

 

可选参数:可选参数后面不允许在出现必须参数

function buildName(firstName:string, lastName?: string) {
    if(lastName){
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');  //第二个参数可以传递

 

参数默认值:TS会将添加了默认值的参数识别为可选参数

function buildName(firstName:string, lastName:string = 'Cat') {
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

 

剩余参数:使用...rest的方式获取函数中的剩余参数

function push(arr, ...items) {
    items.forEach(function(item) {
        array.push(item);
    });
}

let a = [];
push(a, 1, 2, 3);

 

重载:允许一个函数接受不同数量或类型的参数时,做出不同的处理

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if(typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    }else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

 

类型断言

简介:类型断言可以用来手动指定一个值的类型

语法

<类型> 值
值 as 类型
function getLength(something: string | number): number {
    if((<string>something).length) {
        return (<string>something).length;
    } else {
        return something.toString().length;
    }
}
//当ts不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性和方法
//而有时候我们需要在还不确定类型的时候就访问其中一个类型的属性或方法。
//将something断言成string

 

声明文件

新语法索引:使用新语法可在这快速查询

declare var  声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare namespace 声明(含子属性的)全局对象
interface 和 type  声明全局类型
export 导出变量
export namespace  导出(含子属性)对象
export default  ES6默认导出
export = commonjs 导出模块
export as namespace  UMD库声明全局变量
declare global  扩展全局变量
declare module 扩展模块
///<reference />  三斜线指令

(注意:声明语句中只能定义类型,切勿在声明语句中定义具体实现)

 

声明语句

//例:使用jquery获取元素
//js
$('#foo');
//ts  ts编译器不知道$或jquery是什么东西,所以需要定义类型
declare var jQuery:(selector: string) => any;
jQuery('#foo');

 

声明文件

简介:通常把声明语句放在一个单独的文件(例jQuery.d.ts)中,这个文件就是声明文件

声明文件必须以.d.ts为后缀

 

第三方声明文件

@types统一管理第三方库的声明文件

//安装对应声明模块 
npm install @types/jquery --sava-dev

 

书写声明文件

如果第三方库没有提供声明文件,需要自己书写

在不同的场景下,声明文件的内容和使用方式会有所区别。

库的使用场景:

全局变量:通过<script>标签引入第三方库,引入全局变量
npm包: 通过import foo from 'foo' 导入,符合ES6模块规范
UMD库: 即可以通过<script> 标签引入后,改变一个全局变量的结构
直接扩展全局变量:通过<script>标签引入后,改变一个全局变量的结构
在npm包或UMD库中扩展全局变量:引入npm包或UMD库后,改变一个全局变量的结构
模块插件:通过<script>或import导入后,改变另一个模块的结构

 

防止命名冲突

暴露最外层的interface或type会作为全局类型作用域整个项目,应该尽可能减少全局变量或全局类型的数量,将全局变量或类型放到namespace下

//src/jQuery.d.ts
declare namespace jQuery {
    interface AjaxSettings {
        method?: 'GET' | 'POST'
        data?: any;
    }
    function ajax(url: string, settings?: AjaxSettings):void;
}

 

声明合并

如果jQuery即是一个函数,可以直接调用jQuery('#foo'),又是一个对象,拥有子属性jQuery.ajax(),那么我们可以组合多个声明语句,他们可以不冲突地合并起来。

declare funciton jQuery(selector: string): any;
declare namespace jQuery {
    function ajax(url: string, setting?: any): void;
}

 

npm包

一般npm 包的声明文件可能存在两个地方:

  1. 与该npm包绑定在一起
  2. 发布到@types里

如果没有,则需要自己写声明文件,有两种方案

  1. 创建一个node_modules/@types/foo/index.d.ts,存放foo模块的声明文件。无需额外配置,但node_modules目录不稳定
  2. 创建types目录,用来管理自己写的声明文件,将foo声明文件放在types/foo/index.d.ts

npm包声明文件主要的语法:

  • export 导出变量
  • export namespace 导出(含子属性)对象
  • export default ES6 默认导出
  • export = commonjs 导出模块

 

UMD库

简介:既可以通过<script>标签引入,又可以用import引入的库

相对于npm包的类型声明文件,我们需要额外声明一个全局变量,为了实现这个方式,ts提供新语法:

export as namescpce :先有了npm包的声明文件,再基于它添加一条export as namespace语句,即可将声明好的一个变量声明为全局变量。

//types/foo/index.d.ts
export as namespace foo;
export = foo;

declare function foo(): string;
declare namespace foo {
    const bar: number;
}

 

直接扩展全局变量

场景:有的第三方库扩展了一个全局变来那个,可是此全局变量的类型却没有相应的更新过来,就会导致ts编译错误,此时就需要扩展全局变量的类型。

interface String {
    prependHello(): string;
}
'foo'.prependHello();

 

在npm包或UMD库中扩展全局变量

对于npm包或UMD库,如果导入此库之后会扩展全局变量,则需要使用另一种语法在声明文件中扩展全局变量的类型,那就是declare global

//types/foo/index.d.ts
declare global {
    interface String {
        prependHello(): string;
    }
}
export{};  //如果不需要导出任何东西,也需要导出一个空对象,告知编译器这是一个模块的声明文件

 

模块插件

场景:有时import导入一个模块插件,可以改变另一个原有模块的结构。此时如果原有模块已经有了类型声明文件,而插件模块没有类型声明文件,就会导致类型不完整,缺少插件部分的类型。ts提供语法declare module,扩展原有模块的类型

import * as moment from 'moment'
declare module 'moment' {
    export function foo(): moment.CalendarKey;
}

 

声明文件的依赖

场景:一个声明文件有时会依赖另一个声明文件中的类型。对于以上案例使用import导入另一个声明文件的类型外,还有一种语法,三斜线指令(目前不建议用该语法声明模块之间的依赖关系了),使用的场景有如下:

  • 书写一个全局变量的声明文件时
  • 需要依赖一个全局变量的声明文件时
  • 拆分声明文件,当全局变量的声明文件太大时
//types/jquery-plugin/index.d.ts
///<reference types="jquery" />
declare function foo(options: JQuery.AjaxSettings): string;

(注:三斜线指令必须放在文件最顶端,前面只允许出现单行或多行注释

 

自动声明文件

场景:如果库的源码本身是ts写的,用tsc编译时,添加declaration选项,就会同时生成.d.ts声明文件了

{
    "compilerOptions": {
        "module": "commonjs",
        "outDir": "lib",
        "declaration": true
    }
}

 

发布声明文件

发布方案:

  1. 将声明文件和源码放在一起
  2. 将生命文件发布到@types下

参考:

https://ts.xcatliu.com/

https://typescript.bootcss.com/basic-types.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>