TS初学笔记
整理之前学习ts时的一些笔记。
安装
npm install -g typescript // 报无权限
sudo npm install -g typescript
tsc -v // tsc,ts编译器,查看版本
// hello.ts
const hello = (name:string)=>{ return `hello ${name}` }
hello('yuki')
tsc hello.ts //编译 ===> 生成 hello.js
tsc -w hello.ts //监听hello.ts 的变化
node hello.js //运行 js 文件
或者安装 ts-node ,将以上两步合并为一步 ts-node hello.ts
编译后,函数会出现(2393)函数实现重复,猜测可能是vscode的bug(不确定)
在项目根目录添加配置文件 tsconfig.json即可(空文件也可)
基础类型
let isDone: boolean = false;
let age: number = 18;
let firstName: string = "yuki";
let message: string = `Hello,${firstName},age is ${age}`;
let u: undefined = undefined;
let n: null = null;
let num: number = undefined;
any 和 联合类型
let notSure: any = 4;
notSure = "a string";
notSure = true;
notSure.getName();
let numberOrString: number | string;
numberOrString = "hhh";
numberOrString = 1;
数组Array 和 元祖Tuple
// 数组 Array
let arrOfNumbers: number[]=[1,2,3]
arrOfNumbers.push(5)
// 元祖 Tuple
let user:[string,number]=['1',3]
interface 接口
对 对象的形状(shape)进行描述
对 类(class)进行抽象
interface Person {
readonly id:number, // readonly 用于对象属性,不允许修改该值
name: string;
age?: number; // ? 表示 非必须
}
let yuki: Person = {
id:1111,
name: "yuki",
age: 20, // 此处允许不加age
};
yuki.id = 2222 // error , id readonly,不允许修改
函数 和 类型推断
如下,
z 为可选参数。需要注意,必选参数 必须放在 可选参数 之前,否则报错
或者用es6的写法, z:number = 0
,不传的话默认为0
// function add ():number{} 此处的number 规定了输出的类型为number
function add(x:number,y:number,z?:number):number{
if(typeof z ==='number'){
return x+y+z
}
return x+y
}
let result1 = add(1,2,3)
let result2 = add(1,2)
注意,下图中,不是es6中的箭头函数。而是tsc(ts编译器)的 类型推断
image.pnglet str= 'str'
str= 123 // error , 因为ts推断出 str 是string类型
Class 类
默认是public
,允许外部和子类访问
private
不允许外部和子类访问
protected
不允许外部访问,允许子类访问
readonly
可访问,不可修改
class Animal {
private name:string
constructor(name:string){
this.name=name
}
}
const snake = new Animal('lili')
console.log(snake.name) // error,外部不允许访问
snake.name='lucy' // error,外部不允许访问
class Dog extends Animal {
break() {
return `${this.name} is barking`; // error 子类同样无法访问
}
}
子类继承父类,复杂场景时可能无法满足需求,故,可用接口interface提供公共部分
类可以同时继承多个接口,implements
(类继承接口就必须实现这个接口里面写的方法)
接口可以继承接口,extends
interface Radio {
switchRadio():void // void 什么都不返回
}
interface Battery{
checkBatteryStatus()
}
// 方法一:CellPhone 同时implements Radio,Battery
class Car implements Radio {
switchRadio(){ }
}
class CellPhone implements Radio,Battery{
switchRadio(){ }
checkBatteryStatus(){ }
}
// 方法二:RadioWithBattery 继承 Radio, CellPhone implements RadioWithBattery
interface RadioWithBattery extends Radio{
checkBatteryStatus(){ } // 继承了Radio的switchRadio(){ } ,并添加checkBatteryStatus(){ }
}
class CellPhone implements RadioWithBattery{
switchRadio(){ }
checkBatteryStatus(){ }
}
Enum 枚举
默认从0开始赋值,每个值自动递增
也可以自行赋值,number
或 string
等均可
enum Direction {
Up, // 若 赋值 Up=10,则Down为11, Direction[10]为Up
Down,
Left,
Right
}
console.log(Direction.Up) // 0
console.log(Direction[0]) // 'Up' 双向
编译后,可发现转为js后,是一个自执行函数
// js
var Direction;
(function (Direction) {
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
Direction[Direction["Left"] = 2] = "Left";
Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
常量枚举(加const)
const enum Direction {
Up = 'up',
Down = 'down'
}
const value = 'up'
console.log(value === Direction.Up) // true
编译后:
// js
var value = "up";
console.log(value === "up" /* Up */);
常量枚举成员在使用的地方会被内联进来,
之所以可以这么做是因为,常量枚举不允许包含计算成员;
如上,编译时,并没有 Direction 变量的,因此常量枚举会对性能有一定提升。
泛型 (一)
如下,自定义一个泛型T,函数入参类型T,出参同样T(使入参出参保持一样的类型)
当入参为string,出参同样是string;入参为number,出参同样number
function echo<T>(arg: T): T {
return arg;
}
const res = echo("str");
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
const res2 = swap(["str", 123]);
泛型(二):约束泛型
interface IwithLength { length: number; } // 入参必须包含 length属性
function echoWithLength<T extends IwithLength>(arg: T): T {
console.log(arg.length);
return arg;
}
const arr = echoWithLength([1, 2]);
const obj = echoWithLength({ x: 1, length: 1 });
const str = echoWithLength('hhh')
泛型(三):类和接口
class Queue<T> {
private data = [];
push(item: T) {
return this.data.push(item);
}
pop(): T {
return this.data.shift();
}
}
const queue = new Queue<number>();
queue.push(1);
console.log(queue.pop().toFixed());
const queue2 =new Queue<string>()
queue2.push('str')
console.log(queue2.pop())
interface Iplus<T> {
(a: T, b: T): T; // 函数,入参一和入参二为T,出参为T
}
function plus(a: number, b: number): number {
return a + b;
}
function connect(a: string, b: string): string {
return a + b;
}
const num: Iplus<number> = plus;
const str: Iplus<string> = connect;
当我新建另一个ts文件:
let isDone: boolean = false
//报错,提示 'isDone' was also declared here.
在默认状态下,typescript 将 DOM typings 作为全局的运行环境,
当我声明 isDone 时, 与 DOM 中的全局 window 对象下的isDone属性出现了重名。
解决方法:在脚本文件最后一行,添加 export {}; 将文件声明为模块
(在 Typescript 中,只要文件存在 import 或 export 关键字,都被视为 module)
类型别名
使用关键字type,多用于联合
type PlusType = (x: number, y: number) => number;
function sum(x: number, y: number): number {
return x + y;
}
const sum2: PlusType = sum; // 代替 const sum2: (x: number, y: number) => number = sum
类型断言
通过类型断言这种方式告诉编译器类型,只在编译阶段起作用
let someVal: any = 'str'
let strLength: number = (<string>someVal).length // 尖括号
let strLength2: number = (someVal as string).length // JSX 只可使用as语法断言
声明文件
https://www.runoob.com/typescript/ts-ambient.html
目的:为了借用 TypeScript 的各种特性来使用第三方库文件
(declare 定义的类型只会用于编译时的检查,编译结果中会被删除。)
如,
declare var jQuery:(selector:string)=>any
把这些声明单独放在一个文件,称为声明文件,以 .d.ts
为后缀,如 jQuery.d.ts
一般而言,所有ts文件都可获得这些类型定义,若无法获取,可在根路径的tsconfig.json中配置tsc编译器
{ "include":["**/*"] }
DefinitelyTyped (http://definitelytyped.org/)
该组织提供了各类声明文件,安装即可,无需自己创建声明文件
npm install --save-dev @types/jquery