ts的使用

ts的优缺点

优点:

  1. 增强代码的可读性和可维护性
  2. 在编译时即可发现大部分的错误
  3. 强类型

缺点:

  1. 短时间内会增加工作量

环境搭建

安装

npm install -g typescript

可在cmd输入tsc 来查看是否安装成功,安装成功则有反应

可通过tsc +ts文件名将ts文件编译成js文件,然后通过node js文件运行,也可以

npm install -g ts-node

全局安装ts-node,然后ts-node ts文件 运行

ts常见语法

let num: number = 10; // 不能给其他类型的数据,因为已经定义变量未数字类型
let str: string = 'hello world';
let bool: boolean = true;
let udf: undefined = undefined;
let nl: null = undefined;
// ...其他类型依次类推

const arr : string[] = ['小红', '小明']; // 定义了字符串类型的数组,里面的元素只能是字符串
const arrPlus : [string, number, string] = ['hello', 2, 'world']; // 支持多种类型,但是数组必须按照所示类型
const multipleTypesArr : (string | number)[] = ['hello', 'world', 123] // 可以定义多个类型的数组
interface person {
    name: string,
    age: number
}
// 定义了对象,里面包含字符串类型的name和数字类型的age
const XIAO_MING: person = {
    name: '小明',
    age: 18
}

const func: () => boolean = () => {  // 定义了一个函数,必须呀返回一个布尔值
    return true
}

const voidFunc = () : void => {  // 函数没有返回值
    console.log('hello');
}

const nevenFunc = () : never => {  // 函数永远不会执行完(抛出异常,死循环等)
    throw new Error();
    console.log('hello');
}

const addNumber = ({ num1, num2 }: { num1: number, num2: number }) => { // 解构赋值写法
    return num1 + num2;
}

ts类型推断和类型注解

// 当ts可以推断出数据类型的时候(类型推断),就不用限制类型了,否则必须要加类型,类似于上面那种形式(类型注解)
const one = 1;
const two = 2;
const addTotal = (one, two) => {  // 这里推断one和two是any
    return one + two;
}
const total = addTotal(1, 2);

// 但是为了防止有时将函数写成这样
const addTotal = (one, two) => {  // 这里推断one和two是any
    return one + two + '';  // 这个时候返回的结果是string类型
}
const total = addTotal(1, 2);  //自然也是string类型,但是我们实际需要的是number类型,怎么办呢?

const total: number = addTotal(1, 2); // 因为定义的类型和接收到的类型不一样,所以会报错,但是不直观,应该在源头做限制

// 应该写成这样
const addTotal = (one, two): number => {  // 这里推断one和two是any
    return one + two;  // 这个时候如果后面加上字符串的话会报错
}

const total = addTotal(1, 2);

类型别名

type Man = {
    name: string,
    age: number
}

const man: Man= {
    name: '张三',
     age: 18
}
// 也可以这样写
class Man  {
    name: string;
    age: number;
}

const gentleman: Man[]= [{
    name: '张三',
    age: 18
}]

接口(interface)

// 接口的优势,在于可以重复调用,和type的区别:type既可以像interface一样,也可以type Man = string;,而interface只能时像对象一样的格式
interface Women {
    name: string;
    age: number;
    money ?: number; // ?:代表可选
    [propname :string]: any; // 可以接受字符串类型的key,任意类型的value
    say(): string // 必须有一个say方法,返回值时string
}

function a(_: Man) {}
function b(_: Man) {}

function girlFunc(girl: Women):void {
    console.log(girl.name)
    console.log(girl.age)
    console.log(girl.money)
    console.log(girl.husband)
    girl.say();
}

girlFunc({
    name: '小红',
    age: 20,
    money: 100000,
    husband: '小明',
    say() {
        console.log('hello world');
        return 'say'
    }
})

// interface可以限制对象,类和interface
class ClassA implements Women {
    name = '小红';
    age = 20;
    money = 100;
    husband = '小明';
    say() {
        return 'say'
    }
}

interface Teacher extends Women {
    teach(): string
}

function teacherFunc(girl: Teacher):void {
    console.log(girl.name)
    console.log(girl.age)
    console.log(girl.money)
    console.log(girl.husband)
    girl.say();
    girl.teach()
}

teacherFunc({
    name: '小红',
    age: 20,
    money: 100000,
    husband: '小明',
    say() {
        console.log('hello world');
        return 'say'
    },
    teach() {
        return 'teacher'
    }
})

类的使用

class Hero {
    content = '拯救';
    say() {
        return 'say'
    }
}
const hero = new Hero();
console.log(hero.say())

class HeroChild extends Hero {
    // 对say方法的重写
    say() {
        return 'child say'
    }
    sayHello() {
        // 使用super可以继续使用父类的方法
        return super.say() + 'hello world'
    }
    sayAny() {
        return 'any'
    }
}
const child = new HeroChild();
console.log(child.say())
console.log(child.sayAny())
console.log(child.sayHello())

// 类的访问类型

class Student {
    public name: string;  // 访问权限是公开的,默认是public
    private score: number;  // 只能在内部访问
    protected id: number;  // 只有继承的子类可以访问
}

const std = new Student();
std.name = '张三';
// std.score = 100;  // 报错,因为是private权限
// std.id = 1 // 报错

class ClassAStudent extends Student {
    say() {
        console.log(this.id)
    }
}

const classAStd = new ClassAStudent();
classAStd.say()
// classAStd.id = 10; // 报错,因为只能在继承的类中使用

// 类的构造函数
class A {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    // 以上代码可简写成 constructor(public name: string) {},可代替上面四行代码
}
const newA = new A('张三');
console.log(newA.name)

class B extends A {
    public age: number
    constructor(name: string, age: number) {
        super(name) // 一定要写,因为A的构造函数有参数,如果没有参数,需要super()
        this.age = age
    }
}
const newb = new B('李四', 18)
console.log(newb.name);
console.log(newb.age)

// getter,setter, static
class C {
    age: number;
    set cAge(age: number) {
        this.age = age; 
    }
    get cAage() {
        return this.age - 10; // 输出的时候对值进行修改
    }
    static say() {
        console.log('hello')
    }
}
const c = new C();
c.age = 35;
console.log(c.age)
console.log(C.say()) // 可直接通过类调用

类的私有变量和抽象类

abstract class abstractClass {
	abstract skill() // 抽象类中的抽象方法,不用对抽象方法进行描述,但是所有继承的子类都必须要实现这个方法
}

class implementClass extends abstractClass {
	public readonly _name: string; // 只读属性需要前面加上readonly,一般前面加_代表私有变量
	skill() {
		console.log('say hello');
	}
}

tsconfig.json

tsc --init

通过上述指令,可以创建一个tsconfig.json文件,可执行以下指令

tsc  // 将当前所有ts文件按照配置文件编译成js文件
tsc xx.ts  // 只将ts文件编译成js文件,不会按照配置文件编译 

tsconfig 内容

{
	...
	"include": ["xx.ts", "yy.ts"] // 再次执行tsc的时候,只会编译数组中的文件
	“exclude”: ["xx.ts", "zz.ts"] // 除了数组中的ts文件都会编译
	“files”: [] // 效果和include一样
	// "strict": true,  是否严格按照ts规范,只有注释掉下面配置项才起用
	   ...
	    "noImplicitAny": false,   // any类型是否需要书写,为false时可以省略不写                        
 	    "strictNullChecks": true,   // 是否严格检查null,为false时,可以执行类似以下代码 const name: string = null  
 	    "sourceMap": true,   // 是否生成ts和js之间的关系和信息,比如编译后的js文件名时1.js,那么就会生成1.js.map
	    "rootDir": "./", // 要编译的路径
	    "outDir": "./public",  // 要打包的路径   
	    "noUnusedLocals": true,   // 为false时,可以允许变量定义之后不使用                   
        "noUnusedParameters": true,// 为false时,可以允许函数定义之后不使用     
	   ...
	...
}

联合类型和类型保护

interface AnimalA {
    isAnimalA: boolean
    eat: () => {}
}

interface AnimalB {
    isAnimalB: boolean
    sleep: () => {}
}

function handleFunc(animal: AnimalA | AnimalB ) { // 接受的参数类型为两种接口中的任意一种
    // animal.eat() // 会报错,因为animal也可能时AnimalB类型的数据,是没有eat方法的
    // 可以使用以下方法调用
    if ('eat' in animal) {
        animal.eat();
    } else {
        animal.sleep();
    }
}

function add(num1: string | number, num2: string | number) {
    // return num1 + num2; // 会报错,因为string不能和number相加
    if (typeof num1 === 'string' || typeof num2 === 'string') {
        return `${num1} + ${num2}`;
    }
    return num1 + num2;
}

class C {
    count: number
}

function addNum(first: object | C, second: object | C) {
    // return first.count + second.count; // 会报错,因为任意类型的object不一定会有count
    if (first instanceof C && second instanceof C) {
        return first.count + second.count; 
    }
    return 0;
}

#Enum 枚举类型

enum State { // 下标默认是从0开始
    open,  // 0
    close  // 1
}

enum NewState { // 因为有修改默认值,所以是以10开始
    open = 10,  // 10
    close // 11
}

function getState(state: number) {
    if (state === 0) {
        console.log('open')
    } else {
        console.log('close');
    }
}

getState(0);
getState(State.open)
getState(State.close);
console.log(State[1])  // 可以直接得出key,=> close,同样State[0]等于open

泛型

泛型在函数中的使用

// 简单形式
function getNum<T>(num1: T, num2: T) {  // 泛型一般使用T来代表,但是不限定时T,可以起任意名字
    return `${num1} + ${num2}`;
}
getNum<number>(1, 2);

// 数组形式
function getArray<T>(arr: T []) {  // T[] 也可以写成Array<T>
    return arr;
}
getArray<string>(['1', '2'])  // <>中写入类型,泛型不关心函数定义时的类型,而是关心调用的时候的类型,<>里面的类型就是T的类型

// 多个泛型
function getString<T, S> (str: T, num: S) {
    // ...
}
getString<string, number>('hello', 1)

泛型在类中的使用

// 简单形式
class TClass<T> {
    constructor(private users: T[]) {}
    getUser(index: number): T {
        return this.users[index]
    }
}

const users = new TClass<string>(['张三', "李四"])
console.log(users.getUser(0))

// 规定泛型中有某个字段
interface U {
    name: string
}
class TClass<T extends U> {  // 泛型必须继承自U,必须有name字段
    constructor(private users: T[]) {}
    getUser(index: number): string {
        return this.users[index].name
    }
}

const users = new TClass([{ name: '张三' }, { name: '李四' }]) // 需要传对象,并且有name字段
console.log(users.getUser(0))

// 泛型的约束
interface U {
    name: string
}
class TClass<T extends string | number> {  // 泛型必须时string或者number类型
    constructor(private users: T[]) {}
    getUser(index: number): string | number {
        return this.users[index]
    }
}

const users = new TClass(['1', 2]) // 需要传对象,并且有name字段
console.log(users.getUser(0))

命名空间

// 命名空间是为了防止变量冲突而设立的
namespace Page {
    class A {};
    class B {};
    class C {};
    export class All { // 需要导出就用export
        constructor() {
            new A();
            new B();
            new C()
        }
    }
}

这个时候就可以在另外一个文件直接使用(不需要import)

const all = new All()

感谢b站技术胖的视频,原视频地址:https://www.bilibili.com/video/BV1qV41167VD?p=1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值