TypeScriptz學(xué)習(xí)筆記
標(biāo)簽(空格分隔): TypeScript 撩課學(xué)院
安裝TypeScript
cnpm install -g typescript
tsc -v // 查看版本
TypeScript初體驗(yàn)
1. 類型注解
function log(msg) {
console.log('hello' + msg);
}
log('itlike');
log(10);
2. 接口
interface Person {
name: string,
sex: string,
age: number
}
function logPerson(person: Person){
console.log(`姓名: ${person.name}, 性別: ${person.sex}, 年齡: ${person.age}`)
}
let xl = {
name: '小撩',
age: 25,
sex: '女'
}
logPerson(xl);
3. 類
class Dog {
dogName: string;
dogAge: number;
dogSex: string;
constructor(dogName: string, dogAge: number, dogSex: string){
this.dogName = dogName;
this.dogAge = dogAge;
this.dogSex = dogSex;
}
eat(foods: string){
console.log(this.dogName + '在吃' + foods)
}
}
let wc = new Dog('旺財(cái)', 6,'公');
console.log(wc);
wc.eat("蔬菜");
基礎(chǔ)類型
1. 字符串
let dogName: string = '旺財(cái)';
let dogSex: string = '公';
let dogAge: number = 5;
let introDog: string = `
我有一只小狗弧岳,它叫${dogName},
它今年${dogAge}歲凳忙,它是
${dogSex}的
`
console.log(introDog);
2. 數(shù)字
// 2 8 10 16 進(jìn)制
let num1: number = 16;
let num2: number = 0x10;
let num3: number = 0o20;
let num4: number = 0b10000;
console.log(num1, num2, num3, num4);
3. 布爾
let flag:boolean = false;
console.log(flag);
4. 數(shù)組
let numArr: number[] = [1,2,3];
let strArr: string[] = ['張三', '李四', '王五'];
console.log(numArr, strArr);
let boolArr: Array<boolean> = [true, false];
console.log(boolArr);
5. 元組
let tuple: [string, number, boolean, string];
tuple = ['上海', 200, true, '北京'];
console.log(tuple);
let tuple1: [string, number, boolean, string] = ['上海', 200.232323, true, '北京'];
console.log(tuple1[0]);
console.log(tuple1[0].length);
console.log(tuple1[1].toFixed());
console.log(tuple1[2].valueOf());
console.log(tuple1[3].substr(1));
6. 枚舉
自動(dòng)賦值
enum Sex {
Man,
Women
}
let sex1: Sex = Sex.Women;
let sex2: Sex = Sex.Man;
console.log(sex1, sex2);
手動(dòng)賦值
enum Sex {
Man = 2,
Women = 8
}
let sex1: Sex = Sex.Women;
let sex2: Sex = Sex.Man;
console.log(sex1, sex2);
通過枚舉的值得到名字
enum Sex {
Man = 2,
Women = 8
}
let sexName: string = Sex[2];
console.log(sexName);
7. any
let str: any;
str = '我是小撩寶寶';
str = 100;
str = true;
let arr: any[] = ['張三', 19, true, '男'];
arr[3] = 2;
console.log(arr);
8. void
// let str: void = 10; //報(bào)錯(cuò)
let str1: void = null;
let str2: void = undefined;
console.log(str1, str2);
function logMsg(): void {
console.log('it like, like it');
}
logMsg();
9. null和undefined
let str1: null = null;
let str2: undefined = undefined;
let str3: null = undefined;
let str4: undefined = null;
let str5: string = null;
let str6: string = undefined;
console.log(str1, str2, str3, str4, str5, str6);
10. never
function error(msg:string): never{
throw new Error(msg);
}
// error('發(fā)生未知錯(cuò)誤');
// 必須存在無法到達(dá)的終點(diǎn)
function func():never {
while(true){
console.log(1);
}
}
func();
11. object
object的一般使用
let obj1:object = {name: '小撩', age: 18};
console.log(obj1);
console.log(obj1.toLocaleString);
let obj = [1, 2, 3];
console.log(obj);
規(guī)定declare函數(shù)的參數(shù)必須是object
declare function func(o: object): void
func({name: '小撩'}) //OK
func([1,2,3]) //OK
func(null) //OK
func(undefined) //OK
func(123); //報(bào)錯(cuò)
func('小撩'); //報(bào)錯(cuò)
func(true); //報(bào)錯(cuò)
12. 類型斷言
方式一:<>判斷該object是string類型
let obj: any = 'like it, it like';
// let str: string = obj.substr(0, 3);
// console.log(str);
let str2: string = (<string>obj).substr(0, 3);
let str3: string = (<string>obj).toFixed(2);
console.log(str2);
console.log(str3);
方式二:as判斷該object是string類型
let obj: any = 'like it, it like';
let str4: string = (obj as string).substr(0, 4);
console.log(str4);
聲明和解構(gòu)
1. var和let
// 1. var和let
// var存在的幾個(gè)問題
// ①:僅在函數(shù)中才是塊級(jí)作用域
// ②:變量提升
// 因此現(xiàn)在建議多多使用let
var str:string = '撩課';
let str1:string = 'itlike';
// 塊級(jí)作用域
function func(flag: boolean): number{
let a = 99;
if(flag){
// let b = a + 1;
var b = a + 1;
console.log(b);
return b;
}
console.log(b);
return b;
}
func(false);
// 注意
function funcA(x){
let x = 100; //不OK,重復(fù)聲明同一個(gè)變量
var x = 100; //不OK缩筛,重復(fù)聲明同一個(gè)變量
}
function funcB(flag: boolean, x:number): void {
if(flag){
let x = 100; //OK消略,因?yàn)閘et是塊級(jí)作用域堡称,在if里面
}
}
2. const
const CAT_NAME: string = "喵喵";
// CAT_NAME = "哈哈哈"; //錯(cuò)誤
const CAT = {
name: CAT_NAME,
age: 8
}
console.log(CAT);
// 錯(cuò)誤
// CAT = {
// name: '小可愛',
// age: 1
// }
CAT.name = "小黑黑";
console.log(CAT);
3. 解構(gòu)
數(shù)組的解構(gòu)
let arr:number[] = [1,2];
let [one, two] = arr;
console.log(one, two);
// 交換兩個(gè)變量的數(shù)值瞎抛,但是這種方式不嚴(yán)謹(jǐn),盡量少用
[one, two] = [two, one];
console.log(one, two);
// ...符號(hào)
let [first, ...reset] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(reset); // [2, 3, 4, 5]
對(duì)象的解構(gòu)
enum Sex {
Man,
Women
}
interface Person {
personName: string,
personAge: number,
personSex: Sex
}
let person: Person = {
personName: '小撩',
personAge: 19,
personSex: Sex.Women
}
let {personName, personAge, personSex} = person;
console.log(personName, personAge, personSex);
接口
1. 接口的定義和使用
interface Person {
pName: string,
pAge: number,
pJob: string
}
// 初始化person的時(shí)候却紧,變量的順序是無所謂的桐臊,但是名稱和類型必須和接口保持一致
let person: Person = {
pName: '小撩',
pAge: 18,
pJob: '咨詢小姐姐'
}
function printPerson(person){
console.log(`我是:${person.pName}`)
}
printPerson(person);
2. 接口-可選屬性
好處:
- 對(duì)某些屬性進(jìn)行預(yù)定義
- 捕獲錯(cuò)誤
// 輸出接口
interface Circle {
color: string, // 顏色
area: number //面積
}
// 輸入接口
interface CircleConfig {
// 可選屬性
color?: string,
radius?: number
}
function createCircle(config: CircleConfig): Circle{
let newCircle = {color: 'green', area: 100};
if(config.color){
newCircle.color = config.color;
}
if(config.radius){
newCircle.area = Math.PI * config.radius * config.radius;
}
return newCircle;
}
let myCircle1 = createCircle({radius: 100});
console.log(myCircle1);
let myCircle2 = createCircle({color: 'red'});
console.log(myCircle2);
3. 只讀屬性
interface FullName {
readonly firstName: string,
readonly lastName: string
}
let p: FullName = {firstName: '張', lastName: '三豐'};
console.log(p);
console.log(p.firstName, p.lastName);
p.firstName = '李'; // 只讀接口只能進(jìn)行一次賦值胎撤,第二次就會(huì)報(bào)錯(cuò)
console.log(p);
console.log(p.firstName, p.lastName);
只讀數(shù)組
// TS ReadonlyArray<T> Array<T>
let arr:number[] = [1,2,3,4];
arr.push(10);
// arr.pop();
console.log(arr);
let ra: ReadonlyArray<number> = arr;
// ra.push(5); //error
// ra[0] = 10; //error
// ra.length = 1000; //error
console.log(ra);
// 重新將ra賦值給arr,可以使用斷言
arr = ra as number[];
console.log(arr);
4. 額外的類型檢查
4.1 使用斷言
// 輸出接口
interface Circle {
color: string, // 顏色
area: number //面積
}
// 輸入接口
interface CircleConfig {
// 可選屬性
color?: string,
radius?: number
}
function createCircle(config: CircleConfig): Circle{
let newCircle = {color: 'green', area: 100};
if(config.color){
newCircle.color = config.color;
}
if(config.radius){
newCircle.area = Math.PI * config.radius * config.radius;
}
return newCircle;
}
// 這種方式是無法給添加一個(gè)接口中沒有的屬性的
// let myCircle1 = createCircle({color: 'red', radiussss: 100});
// 1. 使用類型斷言
let myCircle1 = createCircle({color: 'red',radius: 11, radiussss: 100} as CircleConfig);
console.log(myCircle1);
4.2 通過字符串的索引簽名(推薦)
// 輸出接口
interface Circle {
color: string, // 顏色
area: number //面積
}
// 輸入接口
interface CircleConfig {
// 可選屬性
color?: string,
radius?: number,
// 字符串的索引簽名
[propsName: string]: any
}
function createCircle(config: CircleConfig): Circle{
let newCircle = {color: 'green', area: 100};
if(config.color){
newCircle.color = config.color;
}
if(config.radius){
newCircle.area = Math.PI * config.radius * config.radius;
}
return newCircle;
}
let myCircle1 = createCircle({color: 'red',radius: 11, radiussss: 100, a: 'q', c: 10});
4.3 對(duì)象賦值
// 輸出接口
interface Circle {
color: string, // 顏色
area: number //面積
}
// 輸入接口
interface CircleConfig {
// 可選屬性
color?: string,
radius?: number,
}
function createCircle(config: CircleConfig): Circle{
let newCircle = {color: 'green', area: 100};
if(config.color){
newCircle.color = config.color;
}
if(config.radius){
newCircle.area = Math.PI * config.radius * config.radius;
}
return newCircle;
}
let circleOption = {color: 'red',radius: 11, radiussss: 100, a: 'q', c: 10};
let myCircle1 = createCircle(circleOption);
5. 函數(shù)類型
interface CompareFunc {
(first: number, last: number): boolean
}
// let myCompare: CompareFunc = function(first: number, last: number): boolean {
// return first > last;
// }
// let myCompare: CompareFunc = function(a: number, b: number): boolean {
// return a > b;
// }
let myCompare: CompareFunc = function(a, b) {
return a > b;
}
console.log(myCompare(10,20));
6. 可索引類型
interface StrArr {
[index: number]: string
}
let myArr:StrArr = ['it', 'like'];
let str:String = myArr[1];
console.log(str);
7. 類類型
7.1 屬性
interface ClockInterface{
currentTime: Date;
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number){
console.log(h, m);
}
}
7.2 描述一個(gè)方法
interface ClockInterface{
currentTime: Date;
setTime(d: Date)
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number){
console.log(h, m);
}
setTime(d: Date){
console.log(d);
}
}
8. 類的靜態(tài)部分 和 實(shí)例部分
8.1 靜態(tài)部分的類型
interface ClockConstructor {
new {h: number, m: number}
}
class Clock implements ClockConstructor {
constructor(h: number, m: number){
}
}
8.2 實(shí)例類型
9. 接口繼承
interface Animal {
// 品種
breed: string
}
interface Cat extends Animal {
// 顏色
color: string
}
let cat = {} as Cat;
cat.breed = '藍(lán)貓';
cat.color = '白色';
console.log(cat);
9.1 一個(gè)接口繼承多個(gè)接口
interface Animal {
// 品種
breed: string
}
interface Mammal {
// 腿的數(shù)量
leg: number
}
interface Cat extends Animal,Mammal {
// 顏色
color: string
}
let cat = {} as Cat;
cat.breed = '藍(lán)貓';
cat.leg = 4;
cat.color = '白色';
console.log(cat);
類
1. 基本使用
var Cat = /** @class */ (function () {
function Cat(catName) {
this.catName = catName;
}
Cat.prototype.say = function () {
return '大家好断凶,我是: ' + this.catName;
};
return Cat;
}());
var cat = new Cat('小黑貓');
console.log(cat);
2. 繼承
class Animal{
animalName: string;
constructor(animalName: string){
this.animalName = animalName;
}
logName(){
return '大家好伤提,我是: ' + this.animalName;
}
}
class Dog extends Animal {
// 品種
breed: string;
constructor(dName: string, breed: string){
super(dName);
this.breed = breed;
}
logBreed(){
return `我的品種是${this.breed}`
}
}
let dog = new Dog('小土豆', '土狗');
console.log(dog);
console.log(dog.animalName, dog.breed);
console.log(dog.logName());
console.log(dog.logBreed());
3. 子類重寫父類中的方法
class Animal{
name: string;
constructor(name: string){
this.name = name;
}
// 走動(dòng)
move(distance: number = 0){
console.log(`${this.name}走動(dòng)了${distance}m`)
}
}
class Snake extends Animal {
constructor(name: string){
super(name);
}
// 走動(dòng)
move(distance: number = 10){
console.log(`我是爬行的......`);
// 調(diào)用父類的方法
super.move(distance);
}
}
class Horse extends Animal {
constructor(name: string){
super(name);
}
// 走動(dòng)
move(distance: number = 500){
console.log(`我是飛奔的......`);
// 調(diào)用父類的方法
super.move(distance);
}
}
let snake:Snake = new Snake('小青蛇');
let horse:Animal = new Horse('白龍馬');
snake.move();
horse.move(70);
4. 公共、私有认烁、受保護(hù)肿男、只讀《修飾符》
4.1 公共的 public
// TS成員默認(rèn)都是public
class Animal{
public name: string;
public constructor(name: string){
this.name = name;
}
public move(distance: number = 0){
console.log(`${this.name}走動(dòng)了${distance}m`);
}
}
4.2 私有的 private
class Animal{
private name: string;
constructor(name: string){
this.name = name;
}
move(distance: number = 0){
console.log(`${this.name}走動(dòng)了${distance}m`);
}
}
let cat = new Animal('小花花');
console.log(cat);
cat.name = "小喵喵"; // 會(huì)報(bào)錯(cuò),name屬性是私有的却嗡,在實(shí)例對(duì)象中也無法使用
cat.move(100);
在TypeScript中舶沛,所有的類都是結(jié)構(gòu)性的
class Animal{
private name: string;
constructor(name: string){
this.name = name;
}
}
class Cat extends Animal{
constructor(name: string){
super('Cat');
}
}
class Dog{
private name: string;
constructor(name: string){
this.name = name;
}
}
// 實(shí)例
let animal = new Animal('豬豬');
let cat = new Cat('小喵喵');
let dog = new dog('dog');
animal = cat;
animal = dog;
cat = dog;
4.3 受保護(hù)的 protected
class Person {
protected name: string;
constructor(name:string){
this.name = name;
}
}
class Employee extends Person{
// 公司
private company: string;
constructor(name: string, company: string){
super(name);
this.company = company;
}
logMsg(){
return `我叫${this.name}, 我在${this.company}工作`
}
}
let p = new Employee('科比', 'NBA');
console.log(p.logMsg());
4.4 readonly修飾符
// 1) 可以使用'readonly'關(guān)鍵字將屬性設(shè)置為只讀的
// 2) 只讀屬性必須在聲明時(shí)或構(gòu)造函數(shù)里被初始化
class Person {
readonly name: string;
constructor(name: string){
this.name = name;
}
}
let person = new Person('小撩');
console.log(person.name);
person.name = '大撩'; // 會(huì)報(bào)錯(cuò)的,readonly修飾的屬性只能賦值一次
5. 參數(shù)屬性
// 參數(shù)屬性可以方便地讓我們在一個(gè)地方定義并初始化一個(gè)成員
// 1) 聲明和賦值合并至一處
// 2) 參數(shù)屬性通過給構(gòu)造函數(shù)參數(shù)前面添加一個(gè)訪問限定符來聲明
class Person {
constructor(public name: string){}
}
let p = new Person('小撩');
p.name = '大撩';
console.log(p.name);
console.log(p);
6. 存取器
- TypeScript支持通過getter/setters來截取對(duì)對(duì)象成員的訪問
- 可以有效地控制對(duì)對(duì)象成員的訪問
注意:
1) >= ES5
2) 如果只實(shí)現(xiàn)了get, 默認(rèn)就是readonly
需求:先檢查密碼是否正確窗价,然后再允許修改員工的信息
// 密碼:
let passCode = 'itLike.com';
class Employee {
private _fullName: string;
get fullName():string {
return this._fullName
}
set fullName(newName:string){
if(passCode && passCode === 'itLike.com'){
this._fullName = newName;
}else{
console.log("錯(cuò)誤: 沒有權(quán)限修改用戶信息如庭!")
}
}
}
let p = new Employee();
p.fullName = '科比';
console.log(p.fullName);
7. 靜態(tài)屬性
- 實(shí)例屬性: 類的實(shí)例成員,僅當(dāng)類被實(shí)例化的時(shí)候才會(huì)被初始化的屬性
- 我們也可以創(chuàng)建類的靜態(tài)成員撼港,這些屬性存在于類本身而不是類的實(shí)例上面
class Company {
// 靜態(tài)屬性
static title = '撩課';
// 實(shí)例屬性
constructor(public college: string){};
// 輸出
fullName(){
return Company.title + this.college;
}
}
let c1 = new Company('web學(xué)院');
console.log(c1.fullName());
let c2 = new Company('Java學(xué)院');
console.log(c2.fullName());
8. 抽象類
抽象類:
1) 抽象類作為其它派生基類使用坪它。
2) 它們一般不會(huì)直接被實(shí)例化。
3) 不同于接口帝牡,抽象類可以包含成員的實(shí)現(xiàn)細(xì)節(jié)往毡。
4) abstract 關(guān)鍵字是用于定義抽象類和在抽象類內(nèi)部定義抽象方法
抽象方法:
1)抽象類中的抽象方法不包含具體實(shí)現(xiàn)并且必須在派生類中實(shí)現(xiàn)
2) 抽象方法的語法與接口方法相似,兩者都是定義方法簽名但不包含方法體
3) 抽象方法必須包含abstract關(guān)鍵字并且可以包含訪問修飾符
abstract class Department {
name: string;
constructor(name: string){
this.name = name;
}
printName():void{
console.log('部門名稱: ' + this.name);
}
// 抽象方法
abstract printMetting():void // 必須在每一個(gè)繼承的派生類中去實(shí)現(xiàn)
}
class AccountingDepartment extends Department {
constructor(){
super('財(cái)務(wù)部');
}
printMetting(): void {
console.log('財(cái)務(wù)部每天10:00開會(huì)');
}
payPage():void {
console.log('每天都發(fā)工資');
}
}
// 約束變量的類型
let department: Department;
// 下面這是錯(cuò)誤的靶溜,抽象類不能直接實(shí)例化
// department = new Department();
department = new AccountingDepartment();
department.printName();
department.printMetting();
department.payPage(); // 錯(cuò)誤: 方法的聲明在抽象類中不存在
9. 把類當(dāng)作接口使用
類定義會(huì)創(chuàng)建兩個(gè)東西卖擅,類的實(shí)例類型和一個(gè)構(gòu)造函數(shù)
因?yàn)轭惪梢詣?chuàng)建出類型,所以能夠在允許使用接口的地方使用類
class Point {
x: number;
y: number;
}
interface Point3D extends Point{
z: number;
}
let point3D: Point3D = {x: 10, y: 20, z: 100};
函數(shù)
1. 基本示例
// 命名函數(shù)
function maxA(x:number, y:number):number{
return x > y ? x : y;
}
// 匿名函數(shù)
let maxB = function (x:number, y:number):number{
return x > y ? x : y;
}
// 箭頭函數(shù)
let maxC = (x: number, y: number) => {
// this
}
let num1:number = 100;
function func(num2, num3):number {
return num1 + num2 + num3;
}
2. 可選參數(shù)
TypeScript 里的每個(gè)參數(shù)都是必須的
這不是指不能傳遞null
或undefined
作為參數(shù)墨技,而是說編譯器檢查用戶是否為每個(gè)參數(shù)都傳入了值
不正確的操作
function max(x: number, y: number):number{
return x > y ? x : y;
}
let res1 = max(10);
let res2 = max(10, 20);
正確的操作
// 可選參數(shù)必須位于必選參數(shù)的后面
function max(x: number, y?: number):number{
if(y){
return x > y ? x : y;
}else {
return x;
}
}
let res1 = max(2);
let res2 = max(2, 4);
console.log(res1, res2);
// 可以預(yù)定義一些參數(shù)的值
function func(x: number, y = 4): void {
console.log(x, y);
}
func(12);
func(2, 1);
func(2, null);
3. 剩余參數(shù)
function sum(x:number, ...resetNumber: number[]):number{
let result:number = x;
for(let i = 0; i < resetNumber.length; i++){
result += resetNumber[i];
}
return result;
}
let result = sum(1,2,3,4,5,6);
console.log(result);
泛型
1. 初體驗(yàn)
function getNumber(num: number):number {
return num;
}
function getNumber(num: any):any {
return num;
}
getNumber(true);
2. 泛型變量
類型變量:它是一種特殊的變量惩阶,只用于表示類型而不是值
function getNumber<T>(num: T):T {
return num;
}
let r1 = getNumber<string>('一百萬');
console.log(r1);
let r2 = getNumber<number>(10);
console.log(r2);
// 調(diào)用的時(shí)候,不寫泛型也是可以的扣汪,這個(gè)只是方便人看
let r3 = getNumber(true);
console.log(r3);
擴(kuò)充
function getNumber<T>(num: T):T {
// 因?yàn)槿绻莕umber類型就沒有l(wèi)ength方法断楷,所以錯(cuò)誤
console.log(num.length);
return num;
}
// 這樣就可以啦
function getNumber<T>(num: T[]):T[] {
console.log(num.length);
return num;
}
3. 泛型類
class Add<T> {
zeroValue: T;
add: (x:T, y:T) => T;
}
// 3.1 number類型
let a = new Add<number>();
a.zeroValue = 100;
a.add(10, 20);
// 3.2 其它類型
let a = new Add<string>(){
a.zeroValue = '2';
a.add('200', '100');
}
4. 泛型約束
有時(shí)候我們想去C座某類型的一組值,并且我們知道這組值具有什么樣的屬性
這時(shí)崭别,可以定義一個(gè)接口來描述約束條件
// 創(chuàng)建一個(gè)包含length屬性的接口
// 通過繼承這個(gè)接口冬筒,在函數(shù)調(diào)用的時(shí)候,參數(shù)必須具有l(wèi)ength這個(gè)屬性茅主,object也可以哦
interface LengthWise {
length: number;
}
function getNum<T extends LengthWise>(num: T):T {
console.log(num.length);
return num;
}
console.log(getNum('10'));
console.log(getNum({value:10, length: 20}));
5. 在泛型約束中使用類型參數(shù)
function getProperty<T, K extends keyof T>(obj: T, key: K){
return obj[key];
}
let person = {name: '小撩', age: 20, sex: '女'};
// 第二個(gè)參數(shù)舞痰,也就是key,只能是person的三個(gè)key
let p1 = getProperty(person, 'name');
let p2 = getProperty(person, 'age');
let p3 = getProperty(person, 'sex');
console.log(p1);
console.log(p2);
console.log(p3);
類型推斷
1. TypeScript 里诀姚,在有些沒有明確指出類型的地方响牛,類型推斷會(huì)幫助提供類型
let num = 10; // 數(shù)字
let str = '撩課'; // 字符串
2. 最佳通用類型
let arr = [0, 10, true, null] // (number | boolean | null)[]
// 如果是class的話,可能不是我們希望的類型
class Animal {
breed: string;
}
class Dog extends Animal{};
class Cat extends Animal{};
let zoo = [new Dog(), new Cat()]; // (Dog | Cat)[],而不是我們希望的Animal[]
// 這個(gè)時(shí)候就可以用強(qiáng)制類型
let zoo:Animal[] = [new Dog(), new Cat()];
3. 上下文類型
1)TypeScript類型推斷會(huì)按另外一種方式呀打,我們稱作“上下文類型”
2)上下文類型的出現(xiàn)和表達(dá)式的類型以及所處的位置相關(guān)
window.onmousedown = function(mouseEvent){
console.log(mouseEvent.target); //OK
console.log(mouseEvent.liaoke); //不OK
}
上下文類型會(huì)在很多情況下使用到
- 通常包含函數(shù)的參數(shù)矢赁,賦值表達(dá)式的右邊,類型斷言贬丛,對(duì)象成員撩银,數(shù)組字面量和返回值語句
- 上下文類型也會(huì)作為最佳通用的候選類型
class Animal {
breed: string;
}
class Dog extends Animal{};
class Cat extends Animal{};
// Animal > Dog > Cat
function createZoo(): Animal[] {
return [new Dog(), new Cat()];
}
高級(jí)特性
1. 聯(lián)合類型:一個(gè)代碼庫希望傳入多種類型的參數(shù)
/*
左側(cè)拼接:
1)如果傳入字符串,則直接拼接
2)如果傳入數(shù)字豺憔,則創(chuàng)建空格拼接
3)其它的為非法
*/
// 1. 編譯通過额获,運(yùn)行報(bào)錯(cuò)
function padLeft(value: string, padding: any){
if(typeof padding === 'number'){
return Array(padding+1).join(' ') + value;
}
if(typeof padding === 'string'){
return padding + value;
}
throw new Error('出現(xiàn)錯(cuò)誤');
}
console.log(padLeft('撩課學(xué)院', 10));
console.log(padLeft('撩課學(xué)院', '3343434343'));
console.log(padLeft('撩課學(xué)院', [21,32,334])); // 編譯通過,運(yùn)行報(bào)錯(cuò)
// 2. 編譯不通過
function padLeft(value: string, padding: string | number){
if(typeof padding === 'number'){
return Array(padding+1).join(' ') + value;
}
if(typeof padding === 'string'){
return padding + value;
}
throw new Error('出現(xiàn)錯(cuò)誤');
}
console.log(padLeft('撩課學(xué)院', 10));
console.log(padLeft('撩課學(xué)院', '3343434343'));
console.log(padLeft('撩課學(xué)院', [21,32,334])); // 編譯不通過
2. 類型保護(hù)
聯(lián)合類型適用于那些值可以為不同類型的情況
但當(dāng)我們想確切地了解pet是否為Fish或者是Bird時(shí)恭应,怎么辦咪啡?
interface Bird{
fly();
sleep();
}
interface Fish{
swim();
sleep();
}
function getSmallPet(): Fish | Bird{
return
}
// 直接寫當(dāng)然是不行的
// let pet = getSmallPet();
// pet.sleep(); // 兩種類型都有sleep方法
// pet.swim(); // Error,比如是Fish類型才可以
// 這樣做暮屡,使用if else也是不行的
// let pet = getSmallPet();
// if(pet.swim){
// pet.swim();
// }else if(pet.fly){
// pet.fly();
// }
// 只能通過使用斷言這種方式了
let pet = getSmallPet();
if(pet as Fish){
(pet as Fish).swim();
}else{
(pet as Bird).fly();
}
3. 自定義的類型保護(hù)
- 類型保護(hù)就是一些表達(dá)式撤摸,它們會(huì)在運(yùn)行時(shí)檢查以確保在某個(gè)作用域里的類型
- 定義一個(gè)類型保護(hù),我們只要簡單地定義一個(gè)函數(shù)褒纲,它的返回值是一個(gè)類型謂詞
interface Bird{
fly();
sleep();
}
interface Fish{
swim();
sleep();
}
function getSmallPet(): Fish | Bird{
return
}
// 謂詞:p is type
function isFish(pet:Fish | Bird): pet is Fish{
return (pet as Fish).swim !== undefined;
}
let pet = getSmallPet();
if(isFish){
pet.swim();
}else{
pet.fly();
}
4. instanceof 類型保護(hù)
instanceof 類型保護(hù)是通過構(gòu)造函數(shù)來細(xì)化類型的一種方式
class Bird{
fly(){
console.log('鳥在飛');
};
sleep(){
console.log('鳥在睡');
};
}
class Fish{
swim(){
console.log('魚在游');
};
sleep(){
console.log('魚在睡');
};
}
function getSmallPet(){
return Math.random() > 0.5 ? new Bird() : new Fish();
}
let pet = getSmallPet();
if(pet instanceof Bird){
pet.fly();
}
if(pet instanceof Fish){
pet.swim();
}
5. 可以為null的類型
- TypeScript具有兩種特殊的類型准夷, null和undefined,他們分別具有值null和undefined
- 默認(rèn)情況下莺掠,類型檢查器認(rèn)為null與undefined可以賦值給任何類型
- 這就意味著:null和undefined是所有其它類型的一個(gè)有效值衫嵌,這也意味著,你阻止不了
將它們賦值給其它類型彻秆,就算是你想要阻止這種情況也不行楔绞。null的發(fā)明者,Tony Hoare唇兑,稱
它為價(jià)值億萬美金的錯(cuò)誤
--strictNullChecks標(biāo)記可以解決此錯(cuò)誤:當(dāng)你聲明一個(gè)變量時(shí)酒朵,它不會(huì)自動(dòng)包含null或undefined
let s = '撩課';
s = null; // 錯(cuò)誤
console.log(s);
let s1:string | null = 'bar';
s1 = null;
console.log(s1);
s1 = undefined; // 錯(cuò)誤
console.log(s1);