美文网首页
TypeScript基础

TypeScript基础

作者: 渚清与沙白 | 来源:发表于2024-01-11 18:00 被阅读0次
类型声明

变量类型声明
参数类型声明
返回值类型声明

声明变量时要指定类型。如:let a: number;
声明变量指定类型并初始化值。如:let a: number = 10;
声明变量自动进行类型检测。如:let a = true;

传参声明类型、返回值声明类型

// 指定参数number类型  指定返回值number类型
function sum(a: number, b: number): number{
  return a + b;
}
基本类型
image.png
  • 字面量
// b只能是二者其一
let b:  "male" | "female";
b = "male";
b = "female";
  • any 与 unknown
    任意类型,一个变量设置类型为any后相当于对该变量关闭了ts对类型的检测
// 显示any
let a: any;
a = 1;
a = "hello";

// 隐式any
let d;
d = 10;
d = true;
d = 'hello';

// 未知类型
let b: unknown;
b = 10;
b = true;

let c: string;
c = d;// 编译通过,此时 c的类型不再是string, 而是any

c = b;// 编译不通过,类型一致

// 类型断言 2种语法
c = d as string;
c = <string> d;

unknown 是一个类型安全的any类型,不能直接赋值给其他类型的变量。一定要赋值需要做类型判断。
any 与 unknown的区别,any类型的变量赋值给其他类型的变量,会改变该变量的类型为any类型。
类型断言,用来告诉解析器变量的实际类型

  • void 与 never
// 返回值为空的函数
function fn(): void{
  return null;// 可以 return null 和 undefined
}
// 没有返回值的函数
function fn2(): never{
  throw new Error("error");
}
  • object
// 声明对象,有name属性类型是string的对象
// ?  可选属性
let a = {name: string, age?: number};
a =  {name: 'A'};

// 普通对象
// 可选属性
let c: {name: string,age?: number} = {name: 'jack'}

// 任意类型的属性
let b: {name: string,[key: string]: any};
b = {name: 'jack', age: 18, gender: 'male'}

// 函数对象
// 声明函数类型的变量 d
let d: (a: number, b: string)=>void;
d = function(a: number, b: string): void {
    console.log(a, b)
}
  • array
// 字符数组
let e: string[] = ['jack', 'rose'];


// number数组  方式一
let f: number[] = [1, 2, 3];
f = [1, 2, 3, 4, 5];

// number数组类型 方式二
let g: Array<number> = [1, 2, 3];
  • 元组
    元组是固定长度的数组
// 元组  长度固定的数组
let h: [string,string] = ['jack', 'rose'];
  • 枚举
// 定义枚举类
enum Color {
    Red,
    Green,
    Blue
}

let i: Color = Color.Red;
if(i === Color.Red){
    console.log('red')
}else if(i === Color.Green){
    console.log('green')
}else if(i === Color.Blue){
    console.log('blue')
}

let j: {name:string, color: Color} = {name: 'jack', color: Color.Red}
  • 联合类型(|) 与 类型别名(type)
// 联合类型  满足其中一种类型即可
let k: string | number = 'jack';
// 须同时满足多个
let l: {name: string} & {age: number} = {name: 'jack', age: 18};

// 类型别名
type myType = string | number | boolean;
let m: myType = 'jack';
编译配置

tsconfig.json

{
    /*
        include: 用来指定哪些ts文件需要被编译
                ** 表示任意目录
                * 表示任意文件
    */

    "include": [
        "src/**/*"
    ],
    // 用来指定哪些ts文件不需要被编译
    "exclude": [
        "node_modules",
        "dist"
    ],
    // 用来指定继承其他tsconfig.json文件
    "extends": "./tsconfig.base.json",
    // 用来指定哪些ts文件需要被编译
    "files": [
        "src/index.ts"
    ],
    "compilerOptions": {
        // 编译为es的版本
        "target": "es5",
        // 指定模块化规范
        "module": "ES6",
        // 指定项目中使用的库
        "lib": [
            "DOM",
            "ES2015"
        ],
        // 编译后的文件存放目录
        "outDir": "./dist",
        // 所有的全局作用域中的代码会合并到同一个文件中
        "outFile": "./dist/index.js",
        // 是否允许编译js文件
        "allowJs": false,
        // 是否检查js代码是否符合语法规范
        "checkJs": false,
        // 是否移除注释
        "removeComments": false,
        // 不生成编译后的文件
        "noEmit": false,
        // 当有错误时不生成编译文件
        "noEmitOnError": false,
        // 设置编译后的文件是否使用严格模式
        "alwaysStrict": false,
        // 不允许出现隐式的any类型
        "noImplicitAny": false,
        // 不允许出现不明确类型的this
        "noImplicitThis": false,
        // 严格检查null值
        "strictNullChecks": false,
        // 所有严格检查的总开关
        "strict": false,
    }
}
继承

构造函数、this、重写方法、super


// 定义一个类
class Person {
    // 声明,构造函数中赋值
    weight: number;
    // 构造函数----对象创建时调用
    constructor(wieght: number) {
        // 构造函数中的 this 指向当前创建的实例对象
        // 可以通过 this 添加属性和方法
        this.weight = wieght;
    }
  
    // 实例属性
    name: string = "蓝色";
    // 静态属性
    static age: number = 18;
    // 只读属性
    readonly height: number = 180;

    // 实例方法
    sayHi() {
        console.log(`你好,我是 ${this.name},我今年 ${Person.age} 岁`);
    }
    // 静态方法
    static sayHi() {
        console.log(`你好,我是 ${Person.age} 岁的 ${Person.name}`);
    }
}

const per = new Person(60);
// 访问实例属性
console.log(per.name);
// 访问静态属性
console.log(Person.age);

// 修改实例属性
per.name = "红色";
Person.age = 20;

// 调用实例方法
per.sayHi();
Person.sayHi();



// extends 继承
// 子类拥有父类所有的属性和方法
class Student extends Person {
    // 子类自有方法  也是一种扩展  遵循开闭原则(OCP,open close principle)
    start() {
        console.log("开始学习");
    }
    // 重写父类的方法,会覆盖父类的sayHi方法
    sayHi() {
        console.log("你好,我是学生");
    }
}
// 子类Teacher
class Teacher extends Person {
    salary: number;
    constructor(weight: number) {
        // 调用父类的构造函数
        super(weight);
        // 初始化子类的属性
        this.salary = 10000;
    }

    teach() {
        console.log("开始教学");
    }
    // 重写 
    sayHi() {
        // 调用父类的 sayHi 方法
        super.sayHi();
        console.log("你好,我是老师");
    }
}

const stu = new Student(20);
stu.sayHi();// 你好,我是学生

const tea = new Teacher(20);
tea.sayHi();// 你好,我是老师

// 构造函数简写形式
class Animal{
    // 语法糖  自动赋值
    constructor(public name: string, public age: number){
    }
}
抽象类

关键字:abstract
抽象类不能用来被创建对象,可以声明抽象方法

// 抽象类
abstract class Animal{
    // 抽象方法  只定义结构  子类必须重写抽象方法
    abstract sayHi(): void;
    // 定义普通方法  
    sayHello(){
        console.log("我是猫");
    }
}

class Cat extends Animal{
    // 重写抽象方法
    sayHi(){
        console.log("我是猫");
    }
}
const cat = new Cat();
// 调用普通方法
cat.sayHello();
// 调用子类重写的方法
cat.sayHi();
接口

定义接口:interface
实现接口:implements
接口之间可以继承,交叉

// 接口  定义一个类的结构
interface IPerson{
    name: string;
    age: number;
    sayHi(): void;
}
// 可以定义多个同名的接口,
interface IPerson{
    gender: string;
}

// IPerson接口类型的对象
const person: IPerson = {
    name: "张三",
    age: 18,
    sayHi() {
        console.log("我是张三");
    },
    gender: "男"
}

// implements 实现接口
class Persons implements IPerson{
    name: string;
    age: number;
    sayHi(): void {
        throw new Error("Method not implemented.");
    }
    gender: string;
    constructor(name: string, age: number, gender: string){
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}

接口继承

interface Point2D{
    x: number;
    y: number;
}
// 接口继承
interface Point3D extends Point2D { 
    z: number;
}
// 实现类
class Point implements Point3D {
    z: number;
    x: number;
    y: number;
    constructor(x: number, y: number, z: number) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

交叉类型
符合:&
功能类似于接口继承,用于组合多个类型为一个类型。
交叉类型与接口继承的区别是在实现类型组合时,处理同名属性冲突的方式不同

interface Person{
    name: string;
}
interface Contact{
    phone: string;
}
// 交叉类型   给交叉类型定义一个别名
type PersonDetail = Person & Contact;
let obj: PersonDetail = {
    name: 'John',
    phone: '15300000000'
}
// 同时实现多个接口
class MyPerson implements Person , Contact{ 
    name: string;
    phone: string;
    constructor(name: string, phone: string){
        this.name = name;
        this.phone = phone;
    }
}
// 实现交叉类型的接口
class My implements PersonDetail{
    name: string;
    phone: string;
    constructor(name: string, phone: string){
        this.name = name;
        this.phone = phone;
    }
}



// 处理同名属性的不同方式
interface A{
    fn:(value:number)=>string;
}
interface B {
    fn:(value:string)=>string;
}
// 交叉类型
type C = A & B;
let c:C = {
    fn:(value:string | number)=>'string'
}

// 接口继承同名属性接口会报错 
interface B extends A{
    fn:(value:string)=>string;// 因属性名与A接口的属性名相同,所以无法进行继承,会报错
}
image.png
索引前面类型 [key: string]
interface AnyObject {
// 只要是属性名是字符串都可以出现在对象中
// 约束属性名只能是字符串,值是number类型
  [key: string]: number;
}   
let obj: AnyObject = {
  a: 1,
  b: 2,
  c: 3,
}
  1. 使用[key: string]来约束改接口中运行出现的属性名称。表示只要是string类型的属性名称都可出现在对象中。
  2. key只是一个占位符
映射类型 [key in type] | [key in keyof]

基于旧类型创建新类型。

// 联合类型  旧类型
type PropKeys = 'x' | 'y' | 'z';
let a: PropKeys = 'x';
// 正常写法
type Type1 = {x: number, y: number, z: number};

// 映射类型  key 必须是 PropKeys类型中的 x , y , z
type Type2 = {[key in PropKeys]: number};

// 类型类型的映射
// 旧对象类型
type Props = {a: number, b: string, c: boolean}
// 新对象类型
type Type3 = {[key in keyof Props]: Props[key]};
let t3: Type3 = {
    a: 1,
    b: '2',
    c: true
}
封装
class  Parent{
    // public       公共属性 在类的内部和外部访问属性和方法
    // private      私有属性 将属性和方法限制为只能在类的内部访问
    // protected    保护属性 在类的内部和子类中可以被访问
    private _name: string;
    private _age: number; 

    constructor(name: string, age: number) {
        this._name = name;
        this._age = age; 
    } 
    // 通过方法 读取 修改属性
    getName() {
        return this._name;
    }
    setName(name: string) {
        this._name = name;
    }
    getAge() {
        return this._age;
    }
    setAge(age: number) {
        if(age < 0) return;
        this._age = age;
    }

    // ts中设置 getter | setter 方法的方式
    get name(){
        return this._name;
    }
    get age(){
        return this._age;
    }
    set name(name: string){
        this._name = name;
    }
    set age(age: number){
        if(age < 0) return;
        this._age = age;
    }
}

const par = new Parent('张三', 18);
// 修改私有属性
par.setName('李四');
// 读取私有属性
const age = par.getAge;

// 修改
par.age = 20;
const ages = par.age;
泛型

function fn<T> (param: T): T{
    console.log(param);
    return param;
}
// 函数调用
// 不指定泛型,TS可以自动推断出类型
fn(10);
// 指定泛型
fn<string>('name');

// 指定多个泛型
function fn2<T, U> (param: T, param2: U): T{
    console.log(param);
    return param;
}
fn2(1,'a');
fn2<string, number>('a', 1);

// 指定接口作为泛型
interface Inter{
    name: string;
}
function fn3<T extends Inter>(p: T): number{
    return Number.parseInt(p.name);
}
// 接口实现类
class CImpl implements Inter{
    name: string;
    constructor(name: string){
        this.name = name;
    }
}
fn3<CImpl>(new CImpl('2'));
两种文件类型
  • .ts文件
  1. 包含类型信息和可执行代码
  2. 可以变编译为.js 文件,执行代码
  3. 用途:编写程序代码的地方
  • .d.ts文件
  1. 只报销类型信息的类型声明文件
  2. 不会生成.js文件,仅用于提供类型信息
  3. 用途:为js提供类型信息

相关文章

网友评论

      本文标题:TypeScript基础

      本文链接:https://www.haomeiwen.com/subject/tyczndtx.html