typescript优点,缺点
优点:
1可以在编译阶段就发现大部分错误,这总比在运行时候出错好
2增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等
3TypeScript 非常包容,.js 文件可以直接重命名为 .ts 即可,即使不显式的定义类型,也能够自动做出类型推论,兼容第三方库.
4TypeScript 拥有活跃的社区.
缺点:
---有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师可能不是很熟悉的概念
---短期可能会增加一些开发成本,毕竟要多写一些类型的定义,不过对于一个需要长期维护的项目,TypeScript 能够减少其维护成本
---集成到构建流程需要一些工作量
----可能和一些库结合的不是很完美
typescript的基本类型
TypeScript学习(四)——变量类型约束(&,|,别名,数组,类型断言,枚举,元祖)
typescript深入
第四节:TypeScript 数组类型
typescript——(private、public、protected、static、abstract、readonly)
TypeScript 中枚举的用法
TypeScript声明文件
---协变,协变是指:子集能赋值给其超集。
class Chordate {
hasSpine(): boolean {
return true;
}
}
class Mammal extends Chordate {
canBreastFeed(): boolean {
return true;
}
}
function foo(animal: Chordate){
animal.hasSpine();
}
foo(new Chordate());
foo(new Mammal());
---逆变
逆变(Contravariance)与双变(Bivariance)只针对函数有效。 --strictFunctionTypes 开启时只支持逆变,关闭时支持双变。
class Chordate {
hasSpine(): boolean {
return true;
}
}
class Mammal extends Chordate {
canBreastFeed(): boolean {
return true;
}
}
declare let f1: (x: Chordate) => void;
declare let f2: (x: Mammal) => void;
f2=f1;
f1=f2; //Error: Mammal is incompatible with Chordate
---双向协变
在老版本的 TS 中,函数参数是双向协变的。也就是说,既可以协变又可以逆变,但是这并不是类型安全的。在新版本 TS (2.6+) 中 ,你可以通过开启 strictFunctionTypes 或 strict 来修复这个问题。设置之后,函数参数就不再是双向协变的了。
type 与 interface 的区别
1. interface仅可以用来定义function, type,interface。而type还可以定义其他number string []等基础类型。
2. interface可以重复定义一个A类型,并且会合并, type不行。
3. interface可以继承interface,继承type,使用extends关键字,type也可继承type,也可继承interface,继承只能使用&。还有类可以实现接口,也可以实现type。
4. interface可以遍历属性名,或者引用
interface和class区别
interface:
1-接口的可选属性
2-函数类型接口
3-可索引接口
类(class):
1.类的静态属性和静态方法
2.抽象方法抽象类
3.多态:父类定义一个基础方法,让继承的每个子类实现不同的功能
4.类含有构造器函数,可以做一些初始化操作。
5.类可以保存状态。
6.类可以做一些ioc控制反转。
泛型
泛型在 TS 中可以说是一个非常重要的属性,它承载了从静态定义到动态调用的桥梁,同时也是 TS 对自己类型定义的元编程。
写TS效率大提升,TypeScript中常用内置工具类型Omit、Pick、Partial、Required、Readonly、Exclude 、Extract
index.d.ts 全局声明
@types/xxx
/// 引入: 比如 /// <reference types="react" />
自己写的包写好ts文件
type拓展
type Name = { name: string };
interface IName { name: string };
----
type Person = Name & { age: number };
interface IPerson extends IName { age: number }
泛型常用运算符
-------
type Pick<T, K extends keyof T> = {
[key in K]: T[key];
}
-------
type Partial<T> = {
[P in keyof T]?: T[P]
}
-------
type Required<T> = {
[key in keyof T]-?: T[P]
}
-------
// Exclude就是判断 T 是否继承于 U,如果是,则返回 never,否则返回 T含有U不含有的。(联合类型是提取T提取不同的,而类也是提取不同的,类我亲自测试的是返回T而不是提取不同的, 有的文章说这里返回T所哟逇其实并不严谨)
// 集合的时候后边是前边的子集,返回前有,后没有
type Exclude<T, U> = T extends U ? never : T;
// Extract 的功能,与 Exclude 相反,它是 提取 T 中可以赋值给 U 的类型(联合类型是T提取相同,而class是全部)。
// 集合的时候后边是前边的子集,返回后边的
-------
type Extract<T, U> = T extends U ? T : never
-------
type Omit = Pick<T, Exclude<keyof T, K>>;
-------
type ReturnType<T extends func> = T extends () => infer R ? R: any;
function getUser() {
return {name: 'xxx', age: 10}
}
type GetUserType = typeof getUser;
type ReturnUser = ReturnType<GetUserType>
-------
Record
interface PageInfo {
title: string;
}
type Page = "home" | "about" | "contact";
const nav: Record<Page, PageInfo> = {
home: { title: "home" },
about: { title: "about" },
contact: { title: "contact" },
};
type Record<K extends string | number | symbol, T> = {
[P in K]: T;
}
{} 任何不为空的对象
--- 联合类型 Exclude使用
type Fruits = "apple" | "banana" | 'peach' | 'orange';
type DislikeFruits = "apple" | "banana";
type FloveFruits = Exclude<Fruits, DislikeFruits> // 等效于 type FloveFruits = "peach" | "orange"
---联合类型 Extract
type Fruits = "apple" | "banana" | 'peach' | 'orange';
type DislikeFruits = "apple" | "banana";
type FloveFruits = Extract<Fruits, DislikeFruits> // 等效于 type FloveFruits = "apple" | "banana"
--- class Extract和Exclude
interface IPerson {
name: string,
age: number,
sex: boolean,
}
interface IMan {
name: string,
age: number,
}
继承关系
type Man = Exclude<IPerson, IMan> // 等效于 type Man = never
type Man = Extract<IPerson, IMan> // 等效于 type Man = IPerson
非继承关系
type Man = Exclude<IMan, IPerson> // 等效于 type Man = {}
type Man = Extract<IMan, IPerson> // 等效于 type Man = never;
------
interface IPerson {
name: string,
age: number,
sex: boolean,
}
interface IMan {
name: string,
age: number,
side: number;
}
非继承关系
type Man = Exclude<IMan, IPerson> // 等效于 type Man = {sex: boolean}
type Man = Extract<IMan, IPerson> // 等效于 type Man = never;
ts类型声明文件的正确使用姿势
typeScript第三篇tsconfig.json配置文件、namespace命名空间、三斜线指令、声明文件d.ts、Mixins混入、装饰器Decorator、Rollup、webpack构建TS
ts中引入 js的理论与实践
useMemo,useCallback
TypeScript 基础类型 —— Null 和 Undefined
declare是干嘛的
ts的.d.ts和declare究竟是干嘛用的
.d.ts 文件中的顶级声明必须以 “declare” 或 “export” 修饰符开头。
通过declare声明的类型或者变量或者模块,在include包含的文件范围内,都可以直接引用而不用去import或者import type相应的变量或者类型。
1.declare声明一个类型
declare type Asd {
name: string;
}
在include包含的文件范围内可以直接使用Asd这个type
2.declare声明一个模块
最经典的声明模块应该是这样了
declare module '*.css';
declare module '*.less';
declare module '*.png';
在编辑ts文件的时候,如果你想导入一个.css/.less/.png格式的文件,如果没有经过declare的话是会提示语法错误的
3.declare声明一个变量
这个什么情况下会用到呢?假如我在项目中引入了一个sdk,这个sdk(我们以微信的sdk为例)里面有一些全局的对象(比如wx),但是如果不经过任何的声明,在ts文件里面直接用wx.config()的话,肯定会报错。
有一句说法我蛮喜欢的:declare就是告诉TS编译器你担保这些变量和模块存在,并声明了相应类型,编译的时候不需要提示错误!
4. declare声明一个作用域
declare namespace API {
interface ResponseList {}
}
声明完之后在其他地方的ts就可以直接API.ResponseList引用到这个接口类型
注意:
1…d.ts文件顶级声明declare最好不要跟export同级使用,不然在其他ts引用这个.d.ts的内容的时候,就需要手动import导入了
2.在.d.ts文件里如果顶级声明不用export的话,declare和直接写type、interface效果是一样的,在其他地方都可以直接引用
declare type Ass = {
a: string;
}
type Bss = {
b: string;
};
自定义组件渲染
import React from 'react';
import ReactDOM from 'react-dom';
let root: HTMLElement | null = document.getElementById('root');
interface Props {
name: string;
}
function Welcome(props: Props): React.ReactElement {
return <h1>Hello, {props.name}</h1>;
}
class Welcome2 extends React.Component<Props> {
render(): React.ReactElement {
return <h1>Hello, {this.props.name}</h1>;
}
}
const element1: React.ReactElement<Props, React.JSXElementConstructor<Props>> = <Welcome name="zhufeng" />;
console.log(element1.props.name);
const element2: React.ReactElement<Props, React.JSXElementConstructor<Props>> = <Welcome2 name="zhufeng" />;
console.log(element1.props.name);
ReactDOM.render(
<div>{element1}{element2}</div>,
root
);
接上边的问题,那么如果定义一个html元素如何理解
let root: HTMLElement | null = document.getElementById('root');//这个是dom元素对象
let root: React.ReactElement | null = <div>ttttttt</div> // 这个当jsx,会转化为react元素
React.FC 等于 React.FunctionComponent
const App: React.FC<{ message: string }> = ({ message }) => (
<div>{message}</div>
);
三斜线指令
/// <reference path="./node.d.ts" />
/// <reference types="node" />
path 类型声明的是对本地文件的依赖,包含路径信息。
types 类型声明的是对 node_modules/@types 文件夹下的类型的依赖,不包含路径信息。
ts 忽略类型检查
单行忽略(添加到特定行的行前来忽略这一行的错误)
// @ts-ignore
跳过对某些文件的检查 (添加到该文件的首行才起作用)
// @ts-nocheck
对某些文件的检查
// @ts-check
禁用 ESLint 语法校验的方法
如何针对单个 js 文件禁用 ESLint 语法校验,但整个项目依然保留 ESLint 的校验规则?
/* eslint-disable */
还可以在注释后加入详细规则,这样就能避开指定的校验规则了
/* eslint-disable no-new */
typescript定义函数的方式
TypeScript——函数(函数定义类型、可选参数和默认参数、剩余参数、函数类型变量、使用接口封装函数变量类型)