前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TypeScript 快速入门

TypeScript 快速入门

作者头像
用户3045442
发布2020-08-06 23:51:24
1.5K0
发布2020-08-06 23:51:24
举报
文章被收录于专栏:Android研究院Android研究院

❝快速入门TypeScript,理解类型系统以及JavaScript自有类型系统的问题 ❞

理解类型系统

理解JavaScript自有类型系统的问题。先要理解以下的类型系统

  • 强类型与弱类型(类型安全)

强类型:语言层面限制函数的实参类型必须与形参类型相同

代码语言:javascript
复制
class Main{
	static void foo(int num){
		System.out.println(num);
	}
	//Main.foo(100)//正确的
	//Main.foo("100")//错误的
}

弱类型:语言层面上不会限制实参的类型

代码语言:javascript
复制
function foo(num){
	console.log(num)
}
//语法上不会报错 可以传入任意类型
foo(100);//ok
foo("100");//ok

由于这种强弱类型之分根本不是某一个权威机构的定义,一般描述强类型有更强的类型约束,而弱类型中几乎没有什么约束。

强类型语言中不允许任意的隐式类型转换,而弱类型语言则允许任意的数据隐式类型转换

变量类型允许随时改变的特点,不是强弱类型的差异

  • 静态类型与动态类型(类型检查)

静态类型:一个变量声明时它的类型就是明确的,声明过后,它的类型就不允许再修改了

动态类型:在运行阶段才能够明确变量类型,而且变量的类型随时可以变化

  • JavaScript自有类型系统的问题

JavaScript 是弱类型且动态类型的语言 【任性】缺失了类型系统的可靠性【不靠谱】

早期JavaScript应用简单,JavaScript是一个脚本语言,没有编译环节的(静态类型语言需要编译 检查的)在大规模应用下,JavaScript的灵活多变的优势,变成了短板。

弱类型的问题:

在小项目中,我们可以通过约定的方式进行设置,但是在大规模项目这种约定就会存在很大的隐患

代码语言:javascript
复制
//JavaScript 弱类型产生的问题
const obj = {}

//运行到此就会报错 抛出异常 这是一个隐患 而强类型的语言直接在语法层面上抛出错误
setTimeout(() => {
    obj.foo();
}, 1000);

//如下 传递不同类型的参数 函数的作用就完全不同了 如果使用强类型的语言 会直接限制参数的类型
function sum(a,b){
   return a+b;
}

sum(100,100);//200
sum(100,"100");//100100

//对象属性名会自动转换为字符串
const obj = {};
obj[true] = 100;
console.log(obj['true']);//对对象索引器的错误用法

强类型的优势:

  • 错误更早暴露
  • 代码更智能,编码更准确
  • 重构更牢靠
  • 减少不必要的类型判断

Flow

Flow 静态类型检查方案

yarn add flow-bin --dev 安装flow

对代码添加标记:// @flow

yarn flow init 初始化flow

yarn flow 执行flow命令检测代码中的类型问题

代码语言:javascript
复制
/*
@flow
*/
function s(num:number):void{
    console.log(num);
}
s(123);

JavaScript 没有编译阶段,直接运行的,而Flow就是给JavaScrip增加了编译阶段来检查类型错误

  • flow 编译移除注解

一般注解类型只是在开发阶段使用,在线上环境是不需要的那么在线上环境的时候需要移除注解,

安装模块:yarn add flow-remove-types --dev

执行命令 :yarn flow-remove-types src -d dist

就会把类型注解去掉生成的代码如下,dist目录下的代码就可以提供到线上使用

代码语言:javascript
复制
function sum(a:number,b:number){
 return a + b;
}

//flow 编译之后的代码 移除类型注解
function sum(a        , b        ) {
    return a + b;
}

sum(100,100);
sum('100','100');
  • babel

yarn add @babel/core @babel/cli @babel/preset-flow --dev 安装babel模块来实现编译移除注解类型

配置.babelrc 文件

代码语言:javascript
复制
{
    "presets": ["@babel/preset-flow"]
}

然后执行:yarn babel src -d dist 将src中的源代码移除类型注解,放到dist目录下

  • flow 开发工具插件

Flow language support 插件vscode 支持检测类型错误 而不用再去运行命令:yarn flow

  • 原始类型
代码语言:javascript
复制
/*
    原始类型
    @flow
*/
const a:string = 'foobar';

const b:number = 100;

const b1:number = NaN;

const b2:number = Infinity;

const c:boolean = true;

const d:null = null;

const e:void = undefined;

const f:symbol = Symbol();

function s():void{
    
}

function ss():number{
    return 100;
}
  • 数组类型
代码语言:javascript
复制
/* 
数组类型
@flow
*/
const arr:Array<number> = [1,2,3];//<T> 泛型

const arr2:number[] = [1,2,3,4];

//固定长度的数组
const foo:[string,number] = ['foo',123];//第一个元素必须是字符串 第二个元素是数字
  • 对象类型
代码语言:javascript
复制
/* 
对象类型
@flow
*/
//定义对象的成员类型方式如下
const obj:{foo:string,bar:number} = {
    foo:'string',bar : 123
}

//上述定义成员类型,成员必须定义否则报错 可以通过?:的方式 成员不是必须定义的
const obj1:{foo?:string,bar:number} = {
    bar:123
}

//设置对象属性键的类型限制和值的类型限制
const obj2:{[string]:string}={}

obj2.key='value';
obj2.age= '14';
  • 函数类型
代码语言:javascript
复制
/* 
函数类型
@flow
*/
//设置函数的参数类型 以及返回值类型
function s(num:number):void{
    console.log(num);
}
s(123);

function ss():number{
    return 100;
}

//回调函数的类型限制(string,number)=>void 参数类型以及返回值类型
function foo(callback:(string,number)=>void){
    callback('zce',123);
}

foo(function(name,num){
    console.log(name,num);
});
  • 特殊类型
代码语言:javascript
复制
/* 
特殊类型
@flow
*/
//字面量类型 a 只能等于foo
const a:'foo'='foo';

//type 可以等于'success' | 'warning' | 'danger'
const type:'success' | 'warning' | 'danger' = 'success';

//同时还可以使用多个类型
type StringOrNumber = string | number;

const b : StringOrNumber = '12';//100

const gender:?number = 100;//? maybe类型 可以接受undefined null
  • 任意类型
代码语言:javascript
复制
/* 
任意类型
@flow
*/

//mixed 强类型 就可以传递任意的类型
function passMixed(value:mixed){
    //需要添加类型判断
    if (typeof value === 'number') {
        value * value;
    }
    if (typeof value === 'string') {
        value.substr(1);
    }
    
}
passMixed(200);
passMixed('100');

//any 弱类型 也可以表示任意类型 一般不推荐使用any
function passAny(value:any){
    //any可以使用任何方法 value 其实还是弱类型的
    value * value;

    value.substr(1);
}
passAny(200);
passAny('100');
  • 运行环境API 类型
代码语言:javascript
复制
/* 
运行环境API 类型
https://github.com/facebook/flow/blob/master/lib/dom.js
@flow
*/
//DOM BOM Node的内置API等 都有一些类型限制
const element:HTMLElement | null =  document.getElementById("id");

以上就是Flow提供的静态类型检查方案,其实TypeScript写法与其类似。

TypeScript

TypeScript解决JavaScript类型系统的问题,TypeScript大大提高代码的可靠程度

TypeScript 可以在任何一个JavaScript中的运行环境中都支持

缺点一:语言本身多了很多概念

缺点二:项目初期,会增加一些成本

TypeScript 属于渐进式的

TypeScript 最终会编译成JavaScript并且支持到ES3的标准

yarn add typescript --dev 项目中添加typescript模块

yarn tsc 01-getting-start.ts 编译ts文件 ,tsc命令就是编译ts文件

代码语言:javascript
复制
/* 
    可以完全按照javascript进行编码
*/
const hello = (name:string) => {
    console.log(`hello ${name}`);
}
hello('zce');

编译后的文件如下:

代码语言:javascript
复制
"use strict";
/*
    可以完全按照javascript进行编码
*/
var hello = function (name) {
    console.log("hello " + name);
};
hello('zce');
//# sourceMappingURL=01-getting-start.js.map
  • TypeScript 配置文件

编译整个项目,创建配置文件:yarn tsc --init

配置文件:TS 还有很多配置 可以自行去官网查阅 下面的配置是常用的配置方式

代码语言:javascript
复制
"target": "es5",//编译后的标准js代码
"module": "commonjs",//模块化
"outDir": "dist",//编译后的目录
"rootDir": "src",//源代码目录
"sourceMap": true,//源代码映射
"strict": true,//开启所有严格检查选项
"lib": ["ES2015","DOM"],//配置标准库 如果要使用ES2015的新的标准就需要引入对应的标准库包括DOM BOM等

命令:yarn tsc 编译整个项目,编译后的js文件就会存放到dist目录中

  • 原始类型在TS中的应用
代码语言:javascript
复制
/* 原始类型在TS中的应用 */

const a:string = 'foo';

const b:number = 100;//NaN Infinity

const c:boolean = true;//false

// const d:string = null;//严格模式下 不允许为null

const e:void = undefined;//严格模式下 不允许为null

const f:null = null;

const g:undefined = undefined;

//如果使用ES5标准库,而这时使用ES6的标准库新的类型会出现错误。
//解决方案一:改为ES2015标准库;
//解决方案二:"lib": ["ES2015","DOM"]
const h:symbol = Symbol();

Array;

Promise;

//DOM API需要在lib中引入DOM
console.log();

//标准库就是内置对象所对应的声明
  • Object类型
代码语言:javascript
复制
export{}

const foo:object = function(){}//[] {} 可以接受对象 数组 函数

//限制对象成员类型 对象的成员
const obj:{foo:number,bar:string} = {foo:123,bar:"string"};
  • 数组类型
代码语言:javascript
复制
const arr1:Array<number> = [1,2,3,];

const arr2:number[] = [1,2,3,];

//---------累加
function sum(...args:number[]){
    //如果使用js就要判断参数是否为Number类型
    //ts只需要添加一个数字的类型注解即可
    return args.reduce((prev,current)=>prev + current,0);
}

// sum(1,2,3,4,'foo');
  • 元组类型

元组:就是一个明确元素数量以及元素类型的一个类型 各个元素的类型不必要完全相同

代码语言:javascript
复制
const tuple:[number,string] = [18,''];//类型不相符 或者超出元素的数量都会报错

const [age,name] = tuple;

//元组类型现在非常常见了
//比如 entries 得到一个键值数组,键值数组就是一个元组[string,number]
//注意entries 属于ES2017的一个标准库
Object.entries({
    foo:123,
    bar:456
});
  • 枚举类型

一般定义类型的写法:

代码语言:javascript
复制
const PostStatus={
    Draft:0,
    Unpublished:1,
    Published:2
}

枚举类型的写法

代码语言:javascript
复制
//默认值是:0开始 依次累加 可以不用指定值
//枚举值可以是字符串 但是字符串无法像数字一样自增长 需要给每一个枚举赋值
//常量枚举 以及 基本枚举的编译情况是不同的 注意
const enum PostStatus{
    Draft,//0
    Unpublished,//1
    Published//2
}

const post={
    title:"Hello TypeScript",
    content:"",
    status:PostStatus.Draft//0 1
}

// PostStatus[0]// => Draft
  • 任意类型
代码语言:javascript
复制
function stringify(value:any){
    return JSON.stringify(value);
}

stringify('100');

stringify(100);
//any 动态类型 ts不会对他进行类型检查
let foo:any = 'string';

foo = 100;

foo.bar();
  • 函数类型
代码语言:javascript
复制
//可选参数或者默认参数 一定在参数列表的最后
function func1(a: number, b?: number,...rest:number[]): string {
  return "func1";
}

func1(100,200);
func1(100);
// func1();

函数表达式,回调函数的约束在TS中可以这样定义:(a:number,b:number) => string

代码语言:javascript
复制
//函数表达式
//回调函数约束
const func2 : (a:number,b:number) => string =  function(a:number,b:number):string{
    return 'func2';
}
  • 隐式类型推断

TypeScript可以自动推荐类型,一旦确定类型就不允许改变类型

代码语言:javascript
复制
let age = 18;//推断为了 number

// age = 'number';//报错

let foo;//没有赋值就是any类型
//可以给任意类型的值 语法上不会报错
foo = 100;

foo = 'string';

//建议每个变量添加更直观的类型
  • 类型断言
代码语言:javascript
复制
const nums = [100,200,199,112];

const res = nums.find(i=>i>1000);//推断res可能找不到

// const square = res * res;
const num1 = res as number;//告诉编译器 我一定是number 不用担心

const num2 = <number>res;
  • 接口

接口 可以约定一个对象的结构,可以约定有哪些成员 TS 只是进行了约束 在编译成JavaScript时实际上没有任何意义和普通对象一样

代码语言:javascript
复制
interface Post {
  title: string;
  content: string;
  //可选成员
  subtitle?: string;
  //只读成员
  readonly summary:string;
}

function printPost(post:Post){
    console.log(post.title);
    console.log(post.content);
}
//subtitle是可选属性 可以不用传入
printPost({title:'hello',content:'a javascript',summary:'12'});

const hello: Post = {
  title: "hello",
  content: "a javascript",
  summary:'A JavaScript'
};

hello.summary = "123";//报错 因为summary属性是一个只读属性 不能修改属性值

定义动态成员的key类型 以及值的类型 定义的成员必须一致否则会报错

代码语言:javascript
复制
interface Cache{
    [prop:string]:string //[prop:string] -> key的类型 :string -> 值的类型
}

const cache:Cache = {}
cache.foo = "value";
// cache.bar = 123;//报错
  • 类 Class

类 描述一类事物的抽象特征 ES6以前通过 函数+原型来模拟的类

class 在ES6中就添加了这一个特性,而TypeScript在ES6的基础上对class添加了访问修饰符,类的属性必须要先声明属性并且必须有一个初始值。

代码语言:javascript
复制
class Person{
    //类的属性必须有初始值 或者构造函数中赋值否则会报错
    public name:string;//默认public 公有属性
    private age:number;//private 私有属性只能在类内部访问
    protected readonly gender:boolean;//protected 保护 只有子类可以访问
    //readonly 只读属性 通过=或者构造函数初始化就不允许再被修改了
    constructor(name:string ,age:number){
        //直接使用this.name 会报错 TS要求明确声明属性 声明的属性必须有初始值可以在=后面赋值,或者在构造函数中对他赋值
        this.name = name;
        this.age = age;
        this.gender = true;
    }
    sayHi(msg:string){
        // this.gender = false;
        console.log(`I am ${this.name} is age:${this.age}`);
    }
    logSay(){
        this.sayHi('你好啊');
    }
}
class Student extends Person{
    //构造函数声明了private 外部就不允许尽心实例化类了
    private constructor(name:string,age:number){
        super(name,age);
        console.log(this.gender);
        //
        // this.gender = false;
    }
    //可以通过内部new实例返回交给外部调用
    static create(name:string,age:number){
        return new Student(name,age);
    }
}

const tom = new Person('tom',18);
console.log(tom.name);
// console.log(tom.gender);
// console.log(tom.age);

// const jake = new Student('jake',18);
const jake = Student.create('jake',18);

类实现接口,代码如下:

代码语言:javascript
复制
interface Eat{
    eat(foo:string):void
}
interface Run{
    run(distance:number):void
}

class Person implements Eat,Run{
    eat(foo:string):void{
        console.log(`优雅的进餐${foo}`);
    }
    run(distance:number):void{
        console.log(`直立行走${distance}`);
    }
}

class Animal implements Eat,Run{
    eat(foo:string):void{
        console.log(`咕噜咕噜的吃${foo}`);
    }
    run(distance:number):void{
        console.log(`爬行${distance}`);
    }
}

抽象类 可以包含一些方法的具体的实现

代码语言:javascript
复制
abstract class Anima{
    eat(foo:string):void{
        console.log(`吃${foo}`);
        
    }
    //抽象方法
    abstract run(d:number):void;
}

class Dog extends Anima{
    //实现父类的抽象方法
    run(d: number): void {
        console.log(`走:${d}`);
    }
}
  • 泛型

TypeScript还引入了泛型的概念

代码语言:javascript
复制
function crateNumberArray(len:number,value:number):number[]{
    //<number> 存放number类型的数据
    const arr = new Array<number>(len).fill(value);
    return arr;
}

const res = crateNumberArray(3,100);
//res => [100,100,100]

//创建string类型的数据
function crateStringArray(len:number,value:string):string[]{
    //<number> 存放number类型的数据
    const arr = new Array<string>(len).fill(value);
    return arr;
}

//通过泛型解决上述代码中的冗余部分

function createArray<T>(len:number,value:T):T[]{
    const arr = new Array<T>(len).fill(value);
    return arr;
}

createArray<number>(1,100);
createArray<string>(10,'10');

TS 与 JS混合开发,涉及到老代码等逻辑,这里就需要用到类型声明,比如一般我们使用的第三方模块 没有用ts实现这时候就需要 使用模块的类型声明

比如lodash的第三方库,提供了类型声明文件,只需要安装即可 npm install @types/lodash

代码语言:javascript
复制
import {camelCase} from 'lodash';

//query-string 模块里面已经包含了类型声明的模块
import qs from 'query-string';

// qs.parse();

//声明函数的类型 明确的声明函数的类型
// declare function camelCase (input:string) : string;

//npm install @types/lodash 或者安装类型声明模块

const r = camelCase('hello worle');
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android研究院 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解类型系统
  • Flow
  • TypeScript
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档