TypeScript 语言

362 阅读6分钟

一、语言类型概述

我们在类型安全方面分为:强类型和弱类型,在类型检查方面分为:静态类型和动态类型。

  • 强类型语言不允许任意的隐式类型转换。
  • 弱类型语言则允许任意的数据隐式类型转换。
  • 静态类型:一个变量声明它的类型就是明确的,变量类型声明过后不许被修改。
  • 动态类型:变量类型声明过后可以被修改。 image.png

JavaScript类型系统特征--弱类型&&动态类型
弱类型有一定的安全隐患
强类型优势
- 错误更早暴露 - 代码更智能,编码更准确 - 重构更牢靠 - 减少不必要的类型判断

Flow--js的类型检查器

二、TypeScript--js的超集

优点:TypeScript支持任何一种js运行环境,功能更强大、生态更健全、更完善。目前angular和vue3都是用ts.
缺点:语言本身多了很多概念,项目初期会增加开发成本

ts编译

npm install typescript -g 进行全局安装
新建1.ts文件
tsc 1.ts 会编译生成一个1.js文件

1.原始类型

const c1: string = 'cbc'
const c2: number = 100
const c2_2: number = NaN
const c2_3: number = Infinity//无穷
const c3: undefined = undefined
const c4: null = null
const c5: boolean = true
const c6: void = undefined
const c7:symbol = Symbol()

自己安装ts使用 但是遇es6语法报错

image.png

target:转换成的目标语言。就是我们通过ts将代码转为那种语言标准。当前例子中是常用的es5. lib:需要被转义的语言。不写的话默认es5。当前例子增加了es6。解决了Symbol报错。dom是解决console的报错。

2.Object类型

//1
const a: Object = {}
const a1: Object = []
const a2: Object = function () { }
//2
const b: {} = {}
const b1: { foo: number, bar: string } = { foo: 123, bar: 'lcj' }

3.数组类型

//1
const a: Array<number> = [1, 2, 3]
//2
const a2: number[] = [1, 2, 3]

4.元组类型

const tuple: [number, string] = [123, 'lcj']
//1
const age = tuple[0]
const name = tuple[1]
console.log(age, name)//123 "lcj"
//2
const [age,name]  = tuple

元组类型例子 image.png

5.枚举类型 -- enum

enum status {
    a = 0,
    b = 1,
    c = 2
}
const post = {
    name: 'xinxin',
    age: status.c
}
console.log(post)//{name: "xinxin", age: 2}

不赋值的话,从0开始自增

enum status {
    a,
    b,
    c
}
const post = {
    name: 'xinxin',
    age: status.c
}
console.log(post)//{name: "xinxin", age: 2}

第一个赋值,接下来自增

enum status {
    a = 8,
    b,
    c
}
const post = {
    name: 'xinxin',
    age: status.c
}
console.log(post)//{name: "xinxin", age: 10}

字符串就正常写,无法自增

enum status {
    a = 'name',
    b = 'age',
    c = 'hobby'
}

6.函数类型

function f1(a: number, b: number):string  { 
    return 'abc'
}
f1(100,10)

可选参数 ?

function f1(a: number, b?: number):string  { 
    return 'abc'
}
f1(100)

或者 设置默认值

function f1(a: number, b: number=10):string  { 
        return 'abc'
    }
    f1(100)

可选参数必须放在参数最后!!!

const f2: (a: number, b: number) => string = function (a: number, b: number): string { 
    return 'fn2'
}

7.任意类型

//1
function f3(value: any) { 
    return value
}
f3('string')
f3(100)
f3(true)
//2
let foo: any = 'string'
foo = 100
foo.bar()

不要轻易使用,因为不会进行类型检查。有时需要兼容老代码,所以可能会使用。

8.隐式类型推断

let age = 18
age = 'weee'//error!! let age: number 不能将类型“"weee"”分配给类型“number”

隐式类型推断age是number类型,所以报错。建议为每个变量添加明确类型!

9.类型断言--as

const nums = [110, 120, 124]
const res = nums.find(i => i > 0)
//推荐使用
const num1 = res as number
//不推荐--因为JSX下不能使用
const num2 = <number>res

10.接口

interface Post { 
    title: string
    content:string
}
function printPost(post: Post) { 
    console.log(post.title)
}

接口可选成员和只读成员

interface Post { 
    title: string
    content: string
    subTiltle?: string //可选成员
    readonly hobby:string //只读成员
}
function printPost(post: Post) { 
    console.log(post.title)
}

动态接口

interface Cache { 
    [prop:string]:string
}
const cache: Cache = {}
cache.foo='val1'

11.类的基本使用

class Person {
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    sayHi(msg: string): void {
        console.log(`i am ${this.name},${msg}`)
    }
}

12.类的访问修饰符

class Person {
    public name: string//默认
    private age: number //私有属性
    protected gender:boolean //受保护的
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
        this.gender = true
    }
    sayHi(msg: string): void {
        console.log(`i am ${this.name},${msg}`)
    }
}
const tom = new Person('tom', 18)
console.log(tom.name)
console.log(tom.age)//error:属性“age”为私有属性,只能在类“Person”中访问。
console.log(tom.gender)//error:属性“gender”受保护,只能在类“Person”及其子类中访问。
class Person {
    public name: string//默认
    private age: number //私有属性
    protected gender:boolean //受保护的
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
        this.gender = true
    }
    sayHi(msg: string): void {
        console.log(`i am ${this.name},${msg}`)
    }
}
class Student extends Person { 
    constructor(name: string, age: number) { 
        super(name, age)
        console.log(this.gender)//ok 可以在子类中访问
    }
}

构造函数的访问修饰符

class Student extends Person { 
    private constructor(name: string, age: number) { 
        super(name, age)
        console.log(this.gender)//ok
    }
}
const jack = new Student()//error:类“Student”的构造函数是私有的,仅可在类声明中访问。
class Student extends Person { 
    private constructor(name: string, age: number) { 
        super(name, age)
        console.log(this.gender)//ok
    }
    static create(name: string, age: number) { 
        return new Student(name, age)
    }
}
const jack = Student.create('jack',10)//ok

private私有的不能在外部实例化和继承,内部创建静态方法,在方法内部实例化,因为只允许在内部被访问。
protected 也不能在外部被实例化,但是可以被继承。

13.类的只读属性

class Person {
    public name: string//默认
    private age: number //私有属性
    protected readonly gender:boolean //受保护的
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
        this.gender = true
    }
    sayHi(msg: string): void {
        console.log(`i am ${this.name},${msg}`)
    }
}

readonly只读属性,内部外部都不允许被修改!

14.类与接口

interface EatAndRun { 
    eat(food: string): void
    run(distance:number):void
}
class Person implements EatAndRun { 
    eat(food: string): void { 
        //...
    }
    run(distance: number): void { 
        //...
    }
}

一个类型约束一个能力,一个类型同时去实现多个接口

interface Eat { 
    eat(food: string): void
}
interface Run { 
    run(distance:number):void
}
class Person implements Eat,Run { 
    eat(food: string): void { 
        //...
    }
    run(distance: number): void { 
        //...
    }
}

15.抽象类

只能被继承不能用new去创建实例对象了,父类中有抽象方法子类必须去实现

abstract class Animal {
    eat(food: string): void {
        //...
    }
    abstract run(distance: number): void
}
class Dog extends Animal { 
    run(distance: number): void { 
        //...
    }
}
const d = new Dog()
d.eat('好东西')
d.run(100)

16.泛型 -- T

在声明函数时先不去定义函数和参数的类型,在调用时在传入确定类型的参数

//只能创建数字类型的
function creatNumArray(lenght: number, value: number): number[] { 
    const arr = Array<number>(lenght).fill(value)
    return arr
}
//泛型 --支持创建任意类型啦
function creatArray<T>(lenght: number, value: T): T[] { 
    const arr = Array<T>(lenght).fill(value)
    return arr
}
const res = creatArray<string>(3,'foo')

17.类型声明

一个成员在被定义是因为某种原因没有明确类型声明,为了考虑兼容一些js模块

image.png

image.png

import { camelCase } from 'lodash'//error :无法找到模块“lodash”的声明文件

declare function camelCase(input: string): string
const res = camelCase('hello abc')

image.png 如果ts中引用第三方模块,如果模块中不包含引用声明文件,可以尝试去安装对应的声明模块,一般是 @types/xxx,如果ts中没有这个模块,那么使用declare去声明所对应的类型!