Typescript基础

11 篇文章 0 订阅

Typescript

TS是JS的超集, TS在JS的基础上加入了类型系统,让参数都有明确的类型,从而带来了更智能的提示。

安装TS
npm install -g typescript
查看版本
tsc -v
编译文件
tsc hello.ts 
#  hello.ts => hello.js
项目安装typescipt
npm i -D typescript ts-loader
生成tsconfig.json配置文件
npx tsc --init
在线编译
类型注解
  • 作用于变量,方法的形参和返回值

TS的基本数据类型

TS的基本数据类型分类

  1. 基础类型
  • string
  • number
  • boolean
  • undefined
  • null
  • symbol
  • bigint
  1. 引用类型
  • object
  • array
  • tuple
  • function
  1. 特殊类型
  • any
  • unknown
  • nerver
  • void
  • enum
  1. 其他类型
  • 类型推理
  • 字面量类型
  • 交叉类型

1. 基础类型

string
let name: string = 'aaa'
number
let num: number = 12
boolean
let status: boolean = true
undefined
  • null 和 undefined 是所有类型的子类型
  • null 和 undefined 两个类型一旦赋值上,就不能在赋值给任何其他类型
let un: undefined = undefined

let name: string // 不报错

let name: string = undefined // 不报错

let name: string = null // 不报错
null
let nu: null = null
symbol
  • symbol是独一无二的,即使声明两个值为一样的symbol, 判断也不相等
let sym: symbol = Symbol();
bigint
let big: bigint = 10n

2. 引用类型

Array
let arr: number[] = [1, 2, 3]

let arr: Array<number> = [1, 2, 3]

let arr: Array<number | string> = ['a', 1, 2] // 多个类型
object
  • object 非原始类型,在定义上直接使用 object 是可以的
 let obj: object = { a: 1, b: 2}
obj.a = 3 // error

let obj2: { a: number, b: number } = {a: 1, b: 2}
obj2.a = 3 // ok
  • Object(大写的O), 代表所有的原始类型或非原始类型都可以进行赋值,除了null和undefined
let obj: Object;
obj = 1; // ok
obj = "a"; // ok
obj = true; // ok
obj = {}; // ok
obj = Symbol() //ok
obj = 10n //ok
obj = null; // error
obj = undefined; // error
tuple
let temp: [number, string] = [1, '2'] // ok
let temp1: [number, string] = [1, 3] // error
let temp2: [number, string] = [1] // error
let temp3: [number, string] = [1, '1', true] // error
function
// function
function add(x: number, y: number): number {
    return x + y;
}

// 箭头函数
let add = (x: number, y: number): number => {
    return x + y;
}

参数类型

  • 可选参数: 如果函数要配置可有可无的参数时,可以通过 ? 实现,可选参数一定要在最后面
  • 默认参数:函数内可以自己设定其默认参数,用 = 实现
  • 剩余参数:仍可以使用扩展运算符 …
// 可选参数
const setInfo = (name: string, age?: number) => {
    console.log(name, age)
}
setInfo('Domesy') //"Domesy",  undefined
setInfo('Domesy', 7) //"Domesy",  7

// 默认参数
const setInfo = (name: string, age: number = 11) => {
    console.log(name, age)
}
setInfo('Domesy') //"Domesy",  11
setInfo('Domesy', 7) //"Domesy",  7

// 剩余参数
const allCount = (...numbers: number[]) => {
    let sum = numbers.reduce((val, item) => (val += item), 0)
    console.log(`数字总和为:${sum}`)
}
allCount(1, 2, 3) //"数字总和为:6"

函数重载

function setInfo(val: string): void {
    console.log(val)
}

function setInfo(val: number): void{
    console.log(val)
}

setInfo("Domesy")

setInfo(7)

3. 特殊类型

any
  • 在 TS 中,任何类型都可以归于 any 类型, 顶级类型
  • 如果不指定变量的类型,则默认为any类型
  • 不推荐使用该类型, 丧失了TS的作用
let val:any // 等价于 let val 
val = '1'
val = 2
val = true
val = [1, 2, 3]
val = {}
unknown
  • unknow只能赋值给unknow类型和any类型,顶级类型
let val:unknown // 等价于 let val 
val = '1'
val = 2
val = true
val = [1, 2, 3]
val = {}

let val1:any // 等价于 let val 
val1 = '1'

let value1:unknown = val //ok
let value2:unknown = val1 //ok

let value4:string = val //error
void
  • 当一个函数,没有返回值时,TS会默认他的返回值为 void 类型

const setInfo = ():void => {} 
// 等价于 
const setInfo = () => {}

const setInfo1 = ():void => { return '1' }  // error
never
  • 表示一个函数永远不存在返回值, never应该是 void子集
  • 符合never的情况有:当抛出异常的情况和无限死循环
let error = ():never => { // 等价约 let error = () => {}
    throw new Error("error");
};

let error1 = ():never => {
    while(true){}
}
枚举
const Status = {
    ONE: 1,
    TWO: 2,
    THREE: 3
}

// 默认从零开始
enum Status {
    ONE, // 0
    TWO, // 1
    THREE, // 2 
}

// 指定开始项的值
enum Status {
    ONE: 1, // 1
    TWO, // 2
    THREE, // 3 
}

// 指定所有项的值
enum Status {
    ONE: 1,
    TWO: 2,
    FOUR: 4,
    NAME: 'name'
}

function getName(name: number): number {
    if (name === Status.ONE) return Status.ONE
    else if (name === Status.TWO) return Status.TWO
    else return Status.THREE
}

其他类型

类型推论
  • 如果没有明确指定类型,ts按照类型推论的规则推断出一个类型
let name // 推断为any

let name = 'rmy' // 推断为 string

 let num = 13; // 推断为 number
字面量类型
  • 在TS中,我们可以指定参数的类型是什么
  • 目前支持字符串、数字、布尔三种类型
let str:'aaa' // aaa 类型
let num: 1 | 2 | 3 = 1 // 1,2,3 类型

str = 'aaa' // ok
num = 2 // ok
num = 7 // error
联合类型
  • 同时指定多个类型,从左往右的或判断
let nameMutilType: (string | number)
交叉类型
  • 将多个类型合并为一个类型,使用&符号连接
type AProps = { a: string }
type BProps = { b: number }

type allProps = AProps & BProps

const Info: allProps = {
    a: 'aaa',
    b: 7
}
interface AProps { a: string }
interface BProps { b: number }

type allProps = AProps & BProps

const Info: allProps = {
    a: 'aaa',
    b: 7
}

接口 和 类型别名

接口 interface

  • 使用接口来描述一个对象,不能描述基础类型
  • 可以继承
  • 可以自动合并声明
// 接口是对一个对象
interface LoginForm {
    username: string,
    password: string,
    phone: (number | string), // 多个类型
    email?: string, // 不确定项
    [propname:string]: any, // 扩展不确定字段
    goto(): string, // 方法
}
let loginForm: LoginForm = {
    username: '',
    password: '',
    phone: '',
}

interface Person {
    name: string,
    age: number
}   
function say(person: Person) {
    return `hello, ${person.name} ${person.age}`
}


// 用于数组
let arr: Person[] = [
    { name: 'rmy', age: 25 }
]

// 继承
interface Student extends Person {
    grade: string,
}

let stu: Student = { 
    name: 'rmy', 
    age: 18, 
    grade: '高三' 
}

// 合并声明
interface User {
    name: string
    age: number
}

interface User {
    sex: string
}

/* 自动合并结果为:
interface User {
    name: string
    age: number
    sex: string
}
*/

类型别名 type

  • 类型别名可以描述基本类型,也可以是对象
  • 可以继承
  • 可以联合类型

// 基础类型
type NameType = string

let name: NameType = 'aaa'

// 对象
type Person = {
    name: string,
    age: number,
}

let user: Person = {
    name: 'rmy',
    user: 25,
}

// 继承 &
type User = Person & {    
    grade: string
}

interface Name {
    name: string 
}

type User = Name & {
    age: number
}

// 联合类型
interface Dog {
    wong()
}

interface Cat {
    miao()
}

type Pet = Dog | Cat

泛型

  • 定义函数/接口/类时不预先指定类型,在使用时再指定具体的类型
// 定义有泛型的函数,T 是接收调用的类型
function identity<T>(arg: T): T {
    return arg
}

// 使用泛型的函数,使用时指定T的类型
let output = identity<string>("myString")


function add<T>(a: T, b: T): T {
    return a + b
}

add<number>(1, 2) 

// 多个泛型

function add<T, P>(a: T, b: P) {
    return `${a}${b}`
}

add<number, string>(1, 'a') // 使用时指定多个泛型

function getPersonAge<T>(person: T): number {
    return person.age
}

getPersonAge<Person>({name: 'rmy', age: 25})

interface IPerson {
    name: string,
    age: number,
}

class Person {
    status: boolean = false
    constructor(person: IPerson) {
        this.name = person.name
        this.age = person.age
    }

    say(content: string) {
        let text: string = `hello,${content}`
        console.log(content)
    }
}

class Student extends Person {
    constructor() {
        super.say('you are welcome') // super 指向父级
    }
}

TS类型断言和类型守卫

TS断言

分为三种:类型断言、非空断言、确定赋值断言

当断言失效后,可能使用到:双重断言

1. 类型断言
  • 类型断言好比其它语言里的类型转换
  • 两种方式:1. 尖括号 2. as
  • 尖括号语法在React中会报错,原因是与JSX语法会产生冲突,所以只能使用as语法
let someValue: number = 1
// 方式一
someValue = (<string>someValue)

// 方式二
someValue = (someValue as string)
2. 非空断言
  • 在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。
const info = (name: string | null | undefined) => {
    const str1: string = name // error name可能是null或者undefined
    const str2: string = name! // ok 
}
3. 确定赋值断言
  • 允许在实例属性和变量声明后面放置一个 ! 号, 以告诉TS该属性会被明确赋值
let num: number;
let num1!: number;

const setNumber = () => num = 7
const setNumber1 = () => num1 = 7

setNumber()
setNumber1()

console.log(num) // error 
console.log(num1) // ok
4. 双重断言
  • 断言失效后,可能会用到,但一般情况下不会使用
  • 失效的情况:基础类型不能断言为接口
interface Info{
    name: string;
    age: number;
}

const name = 'name' as Info; // error, 原因是不能把 string 类型断言为 一个接口
const name1 = 'name' as any as Info; //ok

类型守卫

in关键字
  • 用于判断这个属性是那个里面的
interface Info {
    name: string
    age: number
}

let data: Info = {
    name: 'aaa',
    age: 25
}
if ('name' in data) {
    console.log(`我的名字是:${data.name},年龄是:${data.age}`)
}
typeof关键字
  • 用于判断基本类型,如string, number, boolean, null, undefined等
instanceof关键字
  • 用于判断一个实例是不是构造函数或类的时候
类型谓词(is)
  • is 全等

命名空间 与 模块系统

  • “内部模块” 简称 命名空间
  • “外部模块” 简称 模块
  • 在不同的ts文件里命名同样的变量或方法是会报错的, ts所处的空间是全局的, 使用模块系统可以规避这个问题

1. 命名空间

  • 使用关键字 namespace 定义
  • 提供逻辑分组,避免命名冲突
  • 一个文件里面定义多个命名空间,各个空间可以包含相同的属性和方法
    • 使用模块时就没必要使用命名空间, 因为有模块系统的存在,所以我们平时开发基本上用不到命名空间
// namespace.ts
export namespace SomeNameSpace1 {
  export const name = "rmy";
  export const say = () => {
    console.log("SomeNameSpace1");
  };
}

export namespace SomeNameSpace2 {
  export const name = "rmy";
  export const say = () => {
    console.log("SomeNameSpace2");
  };
}
// 使用
import {SomeNameSpace1, SomeNameSpace2 } from 'namespace.ts'

let name = SomeNameSpace1.name
SomeNameSpace1.say()

2. 模块系统

  • 模块系统是一个逻辑分组
  • TypeScript 与 ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块
  • 模块语法和ES Module中的import和export用法是一样的
// export.ts
export const a = 1

export type Person = {
    name: String
}

export { a, Person }

export default (a = 1)

export default () => 'function'
import { a, Person } from './export';

import * as P from './export';

声明文件

  • 以 .d.ts 结尾的文件就是声明文件
  • 为 JS 代码提供类型声明

声明文件的位置

  • 置到 tsconfig.json 文件中的 include 配置目录中
  • 于 js 代码所在目录相同, 并且文件名也相同的文件
  • 放置到 ```node_modules/@types 文件夹中
  • 手动配置 tsconfig.json 中的 compilerOptions.typeRoots 选项, 配置申明文件的目录

如何编写声明文件

  1. 自动生成
  • 项目是使用 ts 编写的, 在发布(编译)之后是 js 文件
  • 在 tsconfig.json 文件中配置 compilerOptions.declaration : true,编译ts文件就会自动生成声明文件
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值