TypeScript(TS)语法整理

1 篇文章 0 订阅

TypeScript(TS)语法整理


一、简介

TypeScript 是 JavaScript 的超集,包含 ES567等,(有强大的类型系统)
新增了类型系统和完整的面向对象语法
使用 TS 编写的项目更健硕,且更容易扩展和维护,通俗点就是规范

二、TypeScript 环境安装与运行

TS -> JS ,再交给浏览器运行. 类似 Less -> CSS.所以你html里面script标签引用的是index.ts转为js后的index.js文件

打开终端;输入以下命令,就可以看到你的ts跑起来并转为js了:

npm install -g typescript   //全局安装
tsc -v //检查版本,是否安装typescript
tsc --init //初始化,创建 tsconfig.json 文件
// tsc 作用: 负责将 ts 代码 转为 浏览器 和 nodejs 识别的 js 代码如:

//直接运行
tsc index.ts // ts转化为js(使用事例)
tsc --watch index.ts  // 自动监听ts文件改变并转化为js
-------------------------------------------------
//如果是在node中运行
 tsc index.ts
 node index.js//跑起来
 或者
 npm i -g ts-node //一个自动讲ts转为js并运行的node包
 ts-node index.ts// 使用事例
 

在这里插入图片描述

三、TypeScript 使用方法

1. 基本数据类型,联合类型

let age: number = 1313
let age1: string = '1313'
let age2: boolean = true
let a:number|string=111// 联合类型(或)可以是number也可以是string
let age3: undefined = undefined
let age4: null = null
//可以把null undefined赋值给其他类型如:
let num2: number = null//报错把tsconfig.json文件里的严格模式关掉就可以了
//例如for循环
for (let index: number = 0; index < 10; index++) {
    if (index == 6) {
        continue
    }
    console.log(index)

}

2. 数组,元组

//数组
let names: string[] = ['刚刚', '订单']
let names2: number[] = [1, 2]
let names3: Array<number> = [1, 2]//另一种写法
// 任意类型
var arr: any[] = [1, 2, 3, "a", "b", "c"];
//元组,规定类型,长度的数组
let tup: [string, number] = ['刚刚', 3]

3. 枚举

//枚举
enum Color{
    Reds=1,//不赋值默认从0开始,后面递增
    Greens,
    Blues
};
var colorName: string = Color[2]; //访问第二个枚举子元素Green,key值
console.log(colorName);//Greens
colorName = Color[4];
console.log(colorName);//undefined
var c: Color = Color.Greens;//访问第二个枚举子元素Green,value值
console.log(c);//2

4. 函数(void,剩余参数,可选参数,默认值)

// 函数
function warnUser(): void {
    //将函数的返回类型指定为 void,表示该函数不返回任何值
    console.log("This is my warning message");
}
function add(x: number, y: number): number {
    return x + y;
}
console.log(add(1, 2))
function demo3(info: object): object {
    return {
        name: '小红'
    }
}
demo3({ info: 'kkk' })
-----------------------------
//剩余参数
//...args: string[]表示剩余的参数,放在了一个字符串数组中
function greet(x: number, ...args: string[]): string { // 返回一个字符串
    return "Hello World"
}
-------------------------
//将 lastName 设置为可选参数:
function buildName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}
let result1 = buildName("Bob");  // 正确
// let result2 = buildName("Bob", "Adams", "Sr.");  // 错误,参数太多了
let result3 = buildName("Bob", "Adams");  // 正确
---------------------------------
// 设置参数的默认值
function calculate_discoun(price: number, rate: number = 0.50) {
    var discount = price * rate;
    console.log("计算结果: ", discount);
}
calculate_discoun(1000)
calculate_discoun(1000, 0.30)
------------------------
//正常函数表达式完整写法
const add3: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y
}

5. 对象

//对象

let person: {//对象的类型注解
    name: string;
    age: number;
    sayHi: (name: string) => void; //将函数的返回类型指定为 void,表示该函数不返回任何值
    sayHi2: (name: number) => number;
} = {//表示ts中的对象
    name: '啦啦啦',
    age: 18,
    sayHi: function (name: string) {
        console.log('lll')
    },
    sayHi2: function (name: number) {
        return name
    },
}

6. 接口(是一个能力,一种约束)

解决对象类型注解的复用性

interface Users {
    readonly name: string;//只读
    // name:string;
    // age:number;
    age?: number;//?可有可无
}
let p1: Users = {
    name: '啦啦啦',
    age: 18,
}
function Demo(per: Users) {
    return per.name + per.age
}

7. Class

访问修饰符: public/private/protected。
用来修饰描述 类的成员变量 和 成员方法 – 默认是 public(公共的,任何位置都能访问)
private此方法 只允许 在类中访问,不允许在类外面访问,子类也不行。比如说私有方法不能在实例对象中调用
protected此方法 只允许在类中及子类中访问,不允许在类外面访问。比如说私有方法不能在实例对象中调用

class City {
    //定义公共字段(属性)
    readonly a: string = '33';
    b: number;
    constructor(name: string, level: number) {
        this.a = name;
        this.b = level
        // 构造函数中可以修改readonly
    }
    about() {
        console.log('我是父调用的方法', this.a)
    }
}
class Childer extends City {
    constructor(name: string, level: number) {
        super(name, level)
    }
    about() {
        console.log('我是子调用的方法')
        super.about()
    }
}
let cl = new City('哈哈', 5)
cl.about()//我是父调用的方法

8. Class,接口小结

// 小结:接口与接口之间叫继承,类与接口之间叫实现
interface Ifly {
    fly()
}
interface ISwim {
    swim: () => void
}

interface IMy extends Ifly, ISwim { }//1.一个接口可以继承其他接口

class Per implements Ifly {
    //实现接口中的方法
    fly() {
        console.log('class使用接口')
    }
}
//2.一个类可以实现多个接口
class Per2 implements Ifly, ISwim {
    //实现接口中的方法
    fly() { }
    swim() { }
}

9. 类型推论,类型断言

类型推论:
声明变量初始化赋值,函数返回值,可忽略类型注解,ts会自动添加

类型断言:如下

 //querySelector获取id时获取到的是element类型,不能访问到src属性等
 //有点像强制转换
let img = document.querySelector('#image') as HTMLImageElement
console.dir(img)

类型断言有两种写法:
1.<类型>变量名
2.变量 as 类型

function lei(num6: number | string): number {
    if ((<string>num6).length) {
        return (num6 as string).length
    } else {
        return num6.toString().length
  

10. 泛型

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


function createArray<T>(value: T, count: number): any[] {
    const arr: Array<T> = []
    for (let index = 0; index < count; index++) {
        arr.push(value)
    }
    return arr
}
const arr33 = createArray<number>(11, 3)
// <T>(字母可以随便命名)里面就是createArray<number>(11, 3)传的number
----------------------------
//可以传入多个泛型参数
function aa2<P, K>(a: P,b:K): [P,K] {
    return [a,b]
}
aa2<number,string>(1,'a')
-------------------------------
//泛型接口
interface IBase<T>{
    data:Array<T>,//数组的两种写法
    name:T[],
}

class UserB implements IBase<number>{
    data:[1,2];
    name:[1,3]
}
let UserC:IBase<number>={
    data:[1,2],
    name:[1,3]
}
// function UserC:IBase<string>{
    
// }
-------------------------------
//泛型约束
interface Ilength{
    //接口中有一个length属性
    length:number
}
function getLength<T extends Ilength>(x: T): number { // T 为 Ilength的子类型
    return  x.length//此时不知道x有没有length这个属性,所以用泛型约束
}
console.log(getLength<string>('kkk'))
// console.log(getLength<number>(123))报错,因为number没有length

文章案例完整代码

index.ts

四、TypeScript 进阶

1. ! 非空断言操作符

// 忽略变量的 undefined | null:
let myFunc = (maybeString: string | undefined | null) => {
  const onlyString: string = maybeString; // Error,不能将类型“string | null | undefined”分配给类型“string”。不能将类型“undefined”分配给类型“string”。
  const ignoreUndefinedAndNull: string = maybeString!; // Ok
};

2. keyof操作符

// keyof 用于遍历某种类型的属性(可以操作接口、类以及基本数据类型)
// 错误:
 function prop1(obj: object, key: string) {
   return obj[key];
 }
// 我们期望用户输入的属性是对象上已存在的属性,那么如何限制属性名的范围呢?这时我们可以利用 keyof 操作符:
// 正确:
function prop<T extends object, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}
/**
 * 解释:首先定义了 T 类型并使用 extends 关键字约束该类型必须是 object 类型的子类型,
 * 然后使用 keyof 操作符获取 T 类型的所有键,其返回类型是联合类型,
 * 最后利用 extends 关键字约束 K 类型必须为 keyof T 联合类型的子类型
 */

3. type

interface 和 type 很相似,类型定义上,很多时候,用两种方式都能实现。

// interface 和 type 很相似,类型定义上,很多时候,用两种方式都能实现。
/**
 * 1、对于联合类型、元组类型、基本类型(原始值)我们一般使用类型别名type,interface不支持。
 * 2、类型别名type不能extends和implements(class)
 * 3、默认导出方式不同
 * 4、type 能使用 in 关键字进行类型映射,interface不支持
 */
type Keys = "firstname" | "surname";

type DudeType = {
  [key in Keys]?: string;
};

const test6: DudeType = {
  firstname: "Pawel",
  surname: "Grzybek",
};
// 报错
//interface DudeType {
//  [key in keys]: string
//}

4. typeof操作符

// typeof 操作符用于获取变量的类型。因此这个操作符的后面接的始终是一个变量,且需要运用到类型定义当中
type Person = {
  name: string;
  age: number;
};

let man: Person = {
  name: "Semlinker",
  age: 30,
};

type Human = typeof man;
// typeof 和 keyof 一起使用---------
const COLORS = {
  red: "red2",
  blue2: "blue",
};

// 首先通过typeof操作符获取color变量的类型,然后通过keyof操作符获取该类型的所有键,
// 即字符串字面量联合类型 'red' | 'blue'
type Colors = keyof typeof COLORS;
let color: Colors;
color = "red"; // Ok
color = "blue2"; // Ok
// color = "yellow"; // Error ,Type '"yellow"' is not assignable to type '"red" | "blue"'.

5. 函数重载

/**
 * 函数重载:
 * 重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。
 * 每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
 */
function disp(s1: string): void;
function disp(n1: number, s1: string): void;

function disp(x: any, y?: any): void {
  console.log(x);
  console.log(y);
}
disp("abc");
disp(1, "xyz");
//  let suits = ["hearts", "spades", "clubs", "diamonds"];
//  // 定义重载签名
//  function greet(person: string): string;
//  function greet(persons: string[]): string[];
//  // 定义实现签名
//  function greet(person: unknown): unknown {
//      if (typeof person === 'string') {
//          return `Hello, ${person}!`;
//      } else if (Array.isArray(person)) {
//          return person.map(name => `Hello, ${name}!`);
//      }
//      throw new Error('Unable to greet');
//  }
//  console.log(greet(suits[0]));
//  console.log(greet(suits));

6. 联合类型及类型守卫

// 联合类型及类型守卫
type NameOrNameArray = string | string[];
function createName(name: NameOrNameArray) {
  if (typeof name === "string") {
    return name;
  } else {
    return name.join(" ");
  }
}
var greetingMessage = `Greetings, ${createName(["Sam", "Smith"])}`;

// 使用以_开头命名的参数声明不会被未使用参数检查。例如:
function returnNull(_a: any) {  // 正确
  // function returnNull(a:any) {  错误:'a'声明了,但是没有使用
  return null;
}

7. 交叉类型

/**
 * 交叉类型,将多个类型合并为一个类型。
 * 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。
 * 例如, Person & Serializable & Loggable同时是 Person 和 Serializable 和 Loggable。
 * 就是说这个类型的对象同时拥有了这三种类型的成员。
 */
function extend<T, U>(first: T, second: U): T & U {
  let result = <T & U & object>{};
  for (let id in first) {
    (<any>result)[id] = (<any>first)[id];
  }
  for (let id in second) {
    if (!result.hasOwnProperty(id)) {
      (<any>result)[id] = (<any>second)[id];
    }
  }
  return result;
}

class Person2 {
  constructor(public name: string) {}
}
interface Loggable {
  log(): void;
}
class ConsoleLogger implements Loggable {
  log() {
    // ...
  }
}
var jim = extend(new Person2("Jim"), new ConsoleLogger());
var n = jim.name;
jim.log();

8. 命名空间

// 命名空间
namespace some {
  export interface ISome1 {}
  export class Some2 {}
}
/**
 * 命名空间,防止命名冲突:
 * 在书写全局声明文件时,允许在全局作用域里定义很多类型。
 * 我们十分不建义这样做,当一个工程里有许多声明文件时,它会导致无法处理的命名冲突
 */
/// <reference path = "./IShape.ts" />
/// <reference path = "./IShape1.ts" />
/// <reference path = "./IShape2.ts" />
// 三斜线指令仅可放在包含它的文件的最顶端,如果它们出现在一个语句或声明之后,那么它们会被当做普通的单行注释,并且不具有特殊的涵义
function drawAllShapes(shape: Drawing.IShape) {
  shape.draw();
}
// drawAllShapes(new Drawing.Circle());
// drawAllShapes(new Drawing.Triangle());

IShape.ts

namespace Drawing { 
    export interface IShape { 
        draw():void; 
    }
}

IShape1.ts

/// <reference path = "IShape.ts" /> 
namespace Drawing { 
    export class Circle implements Drawing.IShape { 
        public draw() { 
            console.log("Circle is drawn"); 
        }  
    }
}

IShape2.ts

/// <reference path = "IShape.ts" /> 
namespace Drawing { 
    export class Triangle implements Drawing.IShape { 
        public draw() { 
            console.log("Triangle is drawn"); 
        } 
    } 
}

9. 声明文件

/**
 * 声明文件
 * 声明文件以 .d.ts 为后缀
 */
/// <reference path = "Calc.d.ts" />
// 三斜线指令仅可放在包含它的文件的最顶端,如果它们出现在一个语句或声明之后,那么它们会被当做普通的单行注释,并且不具有特殊的涵义
var obj = new Runoob.Calc();
// obj.doSum("Hello"); // 编译错误
console.log(obj.doSum(10));



function isFish(pet: Fish | Bird): pet is Fish {
    return (<Fish>pet).swim !== undefined;
}


Calc.d.ts

/**
 * .d.ts 类似于一个全局类型文件,类型定义文件
 * 在.d.ts文件中声明的变量或者模块,在其他文件中不需要使用import导入,可以直接使用。
 * .d.ts文件中我们常常可以看到declare, declare左右就是告诉TS编译器你担保这些变量和模块存在,并声明了相应类型,
 * 编译的时候不需要提示错误!
 */
// declare global {
//   interface Array<T> {
//     toObservable(): Observable<T>;
//   }
// }

// 声明模块
declare module Runoob {
  export class Calc {
    doSum(limit: number): number;
  }
}
declare module "koa-respond";
declare module "path" {
  export function normalize(p: string): string;
  export function join(...paths: any[]): string;
  export let sep: string;
}
declare module '*.png'
declare module "myLibrary/*";
// import { readFile } from "myLibrary/fileSystem/readFile`;
// readFile(); // readFile是'any'类型

// 声明方法,常量
declare function myLib(a: string): string;
declare const foo: string[] | null;
// 声明枚举
declare enum Enum {
  A = 1,
  B,
  C = 2,
}

//---------------------------
// 声明命名空间
declare namespace cats {
  interface KittySettings {}
}
// interface CatsKittySettings { } //不要

进阶复习案例

  • 11
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

web前端小龚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值