TypeScript

TypeScript 基于JavaScript之上的语言 解决了JavaScript类型系统的问题
  • 强类型与弱类型
  • 静态类型与动态类型
  • Javascript自由类型系统的问题
  • Flow静态类型检查方案
  • TypeScript语言规范与基本应用
类型系统
  • 强类型与弱类型(类型安全) 强类型有更强的类型约束,而弱类型中几乎没有什么约束
    • 强类型语言中不允许任意的隐式类型转换
    • 弱类型语言则允许任意的数据隐式类型转换
  • 静态类型与动态类型(类型检查)
    • 静态类型: 一个变量声明时他的类型就是明确的, 声明过后, 它的类型就不允许再修改
    • 动态类型: 运行阶段才能够明确变量的类型且变量的类型随时可以改变(动态类型中变量没有类型, 变量中存放的值是有类型的)
    • Javascript是动态类型语言
JavaScript类型系统特征
  • 弱类型 且 动态类型 (缺失了类型系统的可靠性) JavaScript没有编译环节
弱类型语言开发大型应用的常见问题
  • 君子约定有隐患, 强制要求有保障
强类型语言的优势
    1. 错误更早的暴露(编译阶段就暴露)
    1. 代码更智能, 编码更准确
    1. 重构更牢靠
    1. 减少不必要的类型判断
Flow
  • JavaScript的类型检查器, 2014年Facebook推出, 弥补js弊端
  • 类型注解: 加参数后边加一个冒号, 在跟上一个数据类型
  • Flow只是一个小工具
Flow编译移除注解
  • 通过编译移除[类型注解]
// @flow
// function sum (a: number, b: number){
//     return a + b
// }

// sum(100, 300)
// sum('100', '300')
// sum('100')

// ==========================


// ==========================

开发工具插件(Flow Language Support)
  • 在vscode中安装插件
类型推断(Type inference)
function square(n){
    return n * n
}
square('100')
类型注解(Type Annotations)
function square(n: number){
    return n * n
}
square('100')
let num: string 
num = 100

function foo(): number {
    return 10
    return '10'
}
// 没有返回值的函数声明类型
function foo(): void {
}
原始类型(Primitive Types)
/**
 * 原始类型
 * @flow
 */

const a: string = 'string'
const b: number = Infinity //NaN // 100
const c: boolean = true //false
const d: null = null 
const e: void = undefined
const f: symbol = Symbol()
数组类型(Array Types)
/**
 * 数组类型
 * @flow
 */

const arr1: Array<number> = [1, 2, 3, 'ee']
const arr2: number[] = [1, 2, 3]

// 元组
const foo: [string, number] = ['foo', 100]
对象类型(Object Types)
/**
 * 对象类型
 * @flow
 */

const obj1: {foo: string, bar: number} = {foo: 'string', bar: 100}
const obj2: {foo?: string, bar: number} = {bar: 100}
const obj3: {[string]: string} = {}
obj3.key1 = 'value3'
obj3.key2 = 100
任意类型(Any Types)
/**
 * Mixed Any 任意类型
 * @flow
 */

// Mixed是强类型的 Any是弱类型

// Mixed
function passMaxid (value: mixed){
    if(typeof value === 'string'){
        value.substr(1)
    }
    if(typeof value === 'number'){
        value * value
    }
}

passMaxid('str')
passMaxid(100)

// Any
function passAny (value: any){
    value.substr(1)
    value * value
}

passAny('str')
passAny(100)
函数类型(Function Types)
/**
 * 函数类型
 * @flow
 */

function foo(callback: (string, number) => void){
    callback('foo string', 100)
}

foo(function(str, num){
    // str => string 
    // num => number
})
特殊类型
/**
 * 运行环境 API
 * @flow
 */

const element: HTMLElement | null = document.getElementById('app')
const element2: HTMLElement | null = document.getElementById(100)
const element1: ?HTMLElement = document.getElementById('app')
类型小结
  • https://flow.org/en/docs/types/
  • https://www.saltycrane.com/heat-sheets/flow-type/latest/
Flow运行环境API(内置对象)
TypeScript JavaScript的超集(superset)、扩展集
  • 任何一种JavaScript运行环境都支持TypeScript
  • 功能更为强大, 生态更健全、更完善(相比Flow)
  • 前端领域的第二语言
  • TypeScript属于[渐进式]
  • 缺点一: 语言本身多了很多概念
  • 缺点二: 项目初期, TypeScript会增加一些成本
快速上手 可以完全按照 JavaScript 辨准语法编写代码
// 可以完全按照 JavaScript 辨准语法编写代码

const hello = (name: string ) => {
    console.log(`hello ${name}`)
}

hello('TypeScript')
hello(100)
TypeScript配置文件 yarn tsc --init
TypeScript原始类型(Primitive Types)
const a: string = 'foo'

const b: number = 100 //NaN Infinty

const c: boolean = true //false

// const d: string = null 

const e: void = undefined

const f: null = null

const g: undefined = undefined

const h: symbol = Symbol()
TypeScript标准库声明(内置对象类型)
  • 标准库: 内置对象所对应的声明
中文错误信息
  • yarn tsc --locale zh-CN (命令行显示中文错误信息)
  • vscode编译器-setting中搜索 typescript locale选项
TS作用域问题
//  02-primitive-types.ts(5, 7): 此处也声明了 "a"
//  const a = 223

// 第一种
// (function(){
//     const a = 223
// })()

// 第二种
const a = 223
export {}
TS的Object类型(Object Types)
const foo: object = function(){} //{} //[]


const obj: {foo: string, bar: number} = {foo: '233', bar: 222}
TS数组类型(Array Types)
const arr1: Array<number> = [2, 3, 4]

const arr2: number[] = [3, 5,3]


 //================
 function sum (...args: number[]){
    return args.reduce((prev, current) => prev + current, 0)
 }

//  sum(2, 3, 2, 'foo')
 sum(2, 3, 2, )
TS元组类型(Tuple Types)
const tuple: [number, string, number] = [1, 'dd', 22]

// const age = tuple[0]
// const name = tuple[0]
const [age, name] = tuple

// ======================
// React 中useState返回的就是元组类型数据
//  Object.entries({name: 'liuchao', age: 22}) 返回的也是元组类型数据(固定长度)
TS枚举类型(Enum Types)
  • 给每一个变量一个更好的名字, 见名知意
  • 一个枚举中只可能出现固定的几个值, 不会出现超出范围的可能性
  • 枚举类型会入侵到运行代码
// const PostStatus = {
//     Draft: 0,
//     Unpublished: 1,
//     Published: 2
// }

// enum PostStatus {
//     Draft = 0,
//     Unpublished = 1,
//     Published = 2,
// }

// 不指定默认值从0开始累加
// eq: Draft = 0, Unpublished = 1 Published = 2
// enum PostStatus {
//     Draft,
//     Unpublished,
//     Published,
// }

// 指定初始的默认值 从初始值开始累加
// eq: Draft = 6, Unpublished = 7 Published = 8
const enum PostStatus {
    Draft = 6,
    Unpublished,
    Published,
}

// 如果枚举类型值是字符串就无法累加, 必须指定每个枚举值
const enum PostStatusStr {
    Draft = 'aaa',
    Unpublished = 'ddd',
    Published = 'ggg',
}

const post = {
    title: 'Hello TS',
    content: 'TS is a typed superset of JavaScript.',
    status: PostStatus.Draft//2, //0 草稿 1 未发布 2 已发布
}




// 枚举类型会入侵到运行代码
// 编译之后会生成一个双向键值对对象 
// 可以通过键获取值 也可以通过值获取键
// var PostStatus;
// (function (PostStatus) {
//     PostStatus[PostStatus["Draft"] = 6] = "Draft";
//     PostStatus[PostStatus["Unpublished"] = 7] = "Unpublished";
//     PostStatus[PostStatus["Published"] = 8] = "Published";
// })(PostStatus || (PostStatus = {}));

// 作用: 可以通过索引获取值
// PostStatus[6] //=> Draft
// console.log(PostStatus[6])


// 如果想去掉这种双向键值对对象 在枚举声明之前加上const
// 编译之后就会消除, 枚举值会在注释中指出
// var post = {
//     title: 'Hello TS',
//     content: 'TS is a typed superset of JavaScript.',
//     status: 6 /* Draft */ //2, //0 草稿 1 未发布 2 已发布
// };
TS函数类型(Function Types)
function func1 (a: number, c: number = 22, b?: number): string {
    return 'func1'
}

// 参数类型、个数必须完全一致
func1(100, 200)
func1(100)
func1(100, 200, 300)

// ========================
const func2:(a: number, b: number) => string = function (a: number, b: number): string {
    return 'func2'
}
任意类型(Any Types)
function stringify (value: any){
    return JSON.stringify(value)
}

stringify('2000')
stringify(222)
stringify(true)

let foo: any = 'string'
foo = 200
foo.bar()

// any类型不安全的
隐式类型推断(Type Inference)
let age = 111
// 不能将类型“string”分配给类型“number”。
// age = 'string'

// 如果不能推断出来变量类型则变量类型为any
let foo 
foo = 22 
foo = 'string'

// 建议为每个变量添加明确的类型 便于理解代码
类型断言(Type assertions)
// 假定这个nums来自一个明确的接口
const nums = [100, 120, 119, 112]

const res = nums.find(i => i>0)

// const square = res * res 

// 断言两种方式
// 第一种 as 推荐
const num1 = res as number 

// 第二种 <> 但是jsx中标签冲突 不能使用
const num2 = <number>res 


const square = num1 * num1 
const square2 = num2 * num2 
接口(Interface)
  • 可选成员、只读成员、动态成员
interface Post {
    title: string
    content: string
    subtitle?: string//可选成员
    readonly summary: string//只读成员
}

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

printPost({
    title: 'hello ts',
    content: 'a js superset',
    summary: 'summary'
})

const hello: Post = {
    title: 'hello ts hello',
    content: 'a js superset hello',
    summary: 'summary hello'
}
// hello.summary = 'hello'



// -----------------------
// 动态成员
interface Cache {
    [key: string]: string
}

const cache: Cache = {}

cache.foo = 'foo'
cache.bar = 'bar'
cache.baz = 'baz'
类 (Classes)
  • 描述一类具体事物的抽象特征
  • Typescript增强类ES6中class的相关语法
  • 访问修饰符
  • 只读属性
class Person {
    // ES2017中新增
    name: string// = 'init name'
    age: number// = 11


    constructor(name: string, age: number) {
        this.name = name
        this.age = age 
    }

    sayHi(msg: string): void {
        console.log(`I am ${this.name}, ${msg}`)
    }
}

// ==================================================
// 访问修饰符
class PersonSync {
    // ES2017中新增
    public name: string// = 'init name' 公有成员 默认 建议加 都可以访问 
    private age: number// = 11  私有属性 只能类的内部访问 不能在外部和子类中访问
    protected gender: boolean //受保护的 只能在子类中访问

    // protected constructor(name: string, age: number) { //protected constructor 不允许实例化 允许继承
    constructor(name: string, age: number) { //protected constructor 不允许实例化 允许继承
        this.name = name
        this.age = age 
        this.gender = true
    }

    sayHi(msg: string): void {
        console.log(`I am ${this.name}, ${msg}`)
    }
}

// protected constructor  不允许实例化
const tom = new PersonSync('tom', 18)
console.log(tom.name)
// 属性“age”为私有属性,只能在类“PersonSync”中访问。
// console.log(tom.age)

// 属性“gender”受保护,只能在类“PersonSync”及其子类中访问。
// console.log(tom.gender)


// constructor  允许继承
class Student extends PersonSync {
    private constructor(name: string, age: number) {// private constructor 不能被实例化 不能被继承
        super(name, age)
        console.log(this.gender, 'gender111')
    }
    static create(name: string, age: number){
        return new Student(name, age)
    }
}

// constructor 不允许实例化
// const student = new Student('liuchao', 10)
// private constructor
const student = Student.create('liuchao', 10)
class Person {
    // ES2017中新增
    public name: string// = 'init name' 公有成员 默认 建议加 都可以访问 
    private age: number// = 11  私有属性 只能类的内部访问 不能在外部和子类中访问
    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}`)
    }
}

const tom = new Person('tom', 18)
console.log(tom.name)
// 抽象类(Abstract Classes)
// 约束子类必须有某一个成员, 不同于接口(interface, 只是成员的抽象, 不包含成员的实现), 抽象类包含成员的实现
// 只能被继承 不能被实例
export {}

abstract class Animal {
    eat(food: string): void{
        console.log(`呼噜噜的吃: ${food}`)
    }
    abstract run(distance: number): void // 抽象方法 abstract function 不需要方法提 子类必须实现
}

class Dog extends Animal{
    run(distance: number):void{
        console.log(`四脚爬行: ${distance}`)
    }
}

const a = new Dog()
a.eat('apple')
a.run(2000)
类与接口
// interface 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{
        console.log(`优雅的进餐: ${food}`)
    }
    run(distance: number): void{
        console.log(`直立行走: ${distance}`)
    }
}

class Animal implements Eat, Run {
    eat(food: string): void{
        console.log(`呼噜噜的吃: ${food}`)
    }
    run(distance: number): void{
        console.log(`爬行: ${distance}`)
    }
}
泛型(Generics)
  • 定义函数接口或类的时候没有具体类型, 使用的时候传递具体类型
function createNumberArray(length: number, value: number): number[]{
    const arr = Array<number>(length).fill(value)
    return arr
}
function createStringArray(length: number, value: string): string[]{
    const arr = Array<string>(length).fill(value)
    return arr
}
function createArray<T>(length: number, value: T): T[]{
    const arr = Array<T>(length).fill(value)
    return arr
}
const res = createNumberArray(3, 1000)
console.log(res)//=> [1000, 1000, 1000]


const res1 = createArray<string>(4, '200')
console.log(res1)
类型声明(Type Declaration)
import { camelCase } from 'lodash'
import qs from 'query-string'

qs.parse('?key=value&key2=value2')


// 未执行npm install @types/lodash 自己声明的类型声明
// declare function camelCase(params:string): string

const res = camelCase('hello typed')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值