安装
npm install typescript -D
tsc终端命令说明
tsc ts文件名 // 将ts文件编译成js文件
tsc ts文件名 -W // 监视ts文件,当ts文件发生改变的时候,自动编译成js文件
tsc // 将根据tsconfig.json文件的配置内容对源文件进行编译
tsconfig.json文件说明
tsconfig.json是ts编译器的配置文件,tsc命令将根据他的信息来对代码进行编译
{
"inclde":[ // 用来指定哪些文件需要被ts编译
"./src/**/*" // **表示任意目录 *表示任意文件
],
"exclude":[ // 用来指定哪些文件不需要被编译,默认值是["node_modules","bower_components","jspm_packages"]
""
],
"extends":"./configs/base", // 基础其他ts配置文件,类似导入吧
"files":[ // 指定需要编译的ts文件
"core.ts"
],
"compilerOptions":{ // 指定ts文件编译的结果
"target":"es2015", // 指定ts文件编译的js版本为es2015(传递错误的值可以获取参考值)
"module":"es2015" , // 指定ts文件的模块化为es2015(如果ts文件含有模块化的代码就需要进行此配置)
"outDir":"./dist", // 用来指定编译后文件的所在目录
"outFile":"./dist/app.js", // 所有全局作用域的代码会合并到同一个文件中
"allowJs":false, // 是否编译js文件 默认为false
"checkJs":true, // 检测js代码是否符合语法,默认为false
"removeComments":false, // 是否移除注释
"noEmit":false, // 是否不生成编译后的文件
"noEmitOnError":true, // 是否当有错误时不生成编译后的文件
"alwaysStrict":false, // 是否使用严格模式
"noImplicitAny":false, // 是否不允许使用隐式使用any类型
"noImplicitThis":false, // 是否不允许使用没有明确类型的this
"strictNullChecks":false, // 是否检查对象可能为null
"strict":true, // 是否所有的严格检查
"baseUrl": "./",
"paths": {
"@/*": ["./src/*"] // 设置别名,注意别名设置后,如果只是单纯用tsc指令编译,不会对编译后的文件路径作出修改,需要用插件。
},
},
"lib":[ // 指定ts文件需要用到的代码提示库,默认包含前端所有用的库例如dom。如果配置了则会覆盖默认值,一般前端项目不需要配置,服务器项目才需要配置
"dom"
],
}
@types/包名 | 第三方声明包的处理
背景:
当我们用 npm 等包管理工具安装第三方包的时候,有些包并不是 TypeScript 编写的,自然也不会导出 TypeScript 声明文件。 这种情况下,如果我们在 TypeScript 项目中引入了这种包,则会编译报错(没有设置 allowJS)。
作用:
安装第三方包的声明文件,能够在ts项目里面使用这些第三方包
工作流程:
比如如下代码:
const user: User = { name: "lucifer" };
Typescript 则会先在本模块查找 User 的定义。
如果找到,则直接返回。 如果找不到, 则会到全局作用域找,而这个全局默认就是指的就是 @types 下的所有类型定义。
(注意目录页是可以配的)
常见的@types/包
@types/node
node环境需要,比如require。
类型声明
联合类型 | &
| 符号
let code : "a" | "b"; // code的赋值只能是a 或者 b
let code : boolean | string // code的赋值只能是boolean或者string类型
& 符号
let code : {name:string} & {age:number};
code = {
name:'xhp',
age :29
}
任意类型 any unkonw
let code : any;
let code : unknow;
他们的区别就是:
定义了any的code,可以接受或赋予所有的变量类型。
定义了unkonw的code,可以接受所有的变量类型,但是只能赋予类型为unkonw或者any的变量
。
例如:
let code1 : any;
let code2 : unknown;
let code3 :string;
code1 = 'asd';
code2 = 'asd';
code3 = code1; // 不会报错
code3 = code2; // 报错,只能赋予赋予类型为unkonw或者any的变量
解决方法:使用类型断言
code3 = code2 as string;
code3 = <string>e;
void类型
函数执行后返回结果的类型
function f1():void{}
never类型
函数执行后返回错误结果的类型
function f1():never{
throw new Error("报错咯")
}
object类型
对象结构的类型声明
let obj : {name:string}; // 指定obj的赋值结构必须只含有name
obj = {name:'xhp'};
let obj : {name:string, age ?: number}; // 指定obj的赋值结构必须含有name age是可选的
obj = {name:'xhp',age:12};
let obj : {name:string, [keyName:string]:any}; // 指定obj的赋值结构必须含有name,其它随意。
obj = {name:'xhp',age:12,age1:'aa'};
fn类型
函数结构的类型声明
let f1 :(a:number, b:number) => number;
f1 = function(a:number, b:number) : number {
return 10
}
数组类型
let array : string[];
let array : Array<string>;
元组类型
它的意思是有固定长度的数组。 let array : [string,string]; // 数组长度为2
枚举类型
指定变量只能从枚举类型里面获取值
enum Gender {
Male = 0,
Female = 1
}
let val : Gender;
val = Gender.Male;
class类型
class Person {
name:string = 'xhp'; // 实例属性(通过新建的对象访问)
static age:number = 18; // 静态属性(类属性,通过类访问)
readonly height:number = 167; // 实例只读属性
sayHello(){} // 实例方法
static sayHi(){} // 静态方法
year:number;
construcotr(year:number){ // 构造函数
this.year = year;
}
}
抽象类abstract class
abstract class Department {
constructor(public name: string) {
}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
constructor() {
super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
}
printMeeting(): void {
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports(): void {
console.log('Generating accounting reports...');
}
}
type类型
类型的别名
type newString = 1 | 2 | 3 | 4 ;
let k : newString
// 等价于
let k : 1 | 2 | 3 | 4 ;
type hellowType = {
name:string
}
let k : hellowType = { name : 'xhp'}
type Fn = (x:number) => number
const fn:Fn = (x:number) => {
return x
}
interface接口类型
对象类型接口
限制引用数据类型的结构
// 定义对象接口类型
interface Obj {
name:string;
[x:string]:any;
}
let obj : Obj = { name : 'xhp', xxx:1}
// 定义数组接口类型
interface ArrayStr {
[x:number]:string;
}
let array : ArrayStr = ['1']
函数类型接口
interface Fn {
(x: number, y: number): number
}
let fn: Fn = (a,b) => a+b
type、interface区别
- type 声明需要带 = 号,interface 不需要。
- type 不可以重复声明。interface可以,interface重复声明不是覆盖,而是合并。
- type能用来修饰普通数据类型和引用数据类型,interface只能修饰引用数据类型
- type函数与interface函数的格式是不一样的。
interface Fn {
(x: number, y: number): number
}
type Fn = (x: number, y: number) => number
< T >泛型
不预先确定数据类型,具体的类型在使用的时候才能确定。
普通泛型
function log<T>(value:T):T {
return value
}
log<string>('1')
log<number>(1)
log<number[]>([1])
接口泛型
interface Fn<T> {
(x:T) : T
}
const fn:Fn<number> = function (x:number):number {
console.log(x)
return x
}
// 使用默认
interface Log<T = string>{
(value:T):T
}
let mylog:Log = (value:T):T {
return value
}
mylog('1')
type泛型
type Fn<T> = (x:T) => T
const fn:Fn<number> = (x:number) => {
return x
}
类型兼容性
接口兼容性,右边的属性大于左边的属性
interface Left {
a:number,
b:number,
}
interface Right {
a:number,
b:number,
c:number,
}
let left:Left = {
a: 0,
b: 0
}
let right:Right = {
a: 0,
b: 0,
c: 0
}
left = right
函数兼容性,右边的属性要小于左边的属性
let leftFn = function (a: number) { }
let rightFn = function (a: number,b:number) { };
rightFn = leftFn;
&交叉类型
合并多个接口类型。
注意,如果不同接口但是多个key相同,如果key的类型不一致,使用会报错。
interface A {
a:number
}
interface B {
b:number
}
interface C {
a:string
}
const abc : A & B = {
a:1,
b:2,
}
// 报错
const abc1 : A & B & C = {
a:1,
b:2,
}
|联合类型
限制变量类型要么a,要么b。
// 限制变量的数据类型
let a: number | string = 1
// 限制变量值的范围
let b: 1 | 2 | 3 | 4;
b = 1
interface D {
a:number,
b:number
}
interface E {
c:number
d:number
}
const xx: D | E = {
c: 1,
d: 1,
}
console.log(xx)
// 可区分的联合类型
interface A {
a: number,
c: number,
name: 'A'
}
interface B {
b: number,
c: number,
name: 'B'
}
function test(ab: A | B) {
switch (ab.name) {
case 'A':
ab.a
break;
case 'B':
ab.b
break;
}
}
extends的作用
1、接口继承
interface Shape {
color: string;
}
interface Circle extends Shape {
radius: number;
}
const myCircle: Circle = {
color: "red",
radius: 5
};
2、泛型约束
限制它必须是某种类型的子类型。
type A<T> = T extends string ? number : boolean
// 如果T是string(也就是T是string的子类型),那么就是number类型,否则就是boolean类型
type A1 = A<string> // A1 = number
type A2 = A<string | number> // A2 = boolean
TS内部自定义的api
1、keyof
取interface所有的key为联合类型
interface KeyOfData {
a: string;
b: number;
}
type KeyOfData1 = keyof KeyOfData
const t1:KeyOfData1 = 'a'
/**********原生实现*************/
type KeyOfData2 = 'a' | 'b'
const t2:KeyOfData2 = 'a'
2、Readonly
将interface所有的key设置为只读类型
interface ReadOnlyData1 {
a: string;
b: number;
}
type ReadOnlyData2 = Readonly<ReadOnlyData1> // { readonly a: string; readonly b: string; }
/********************原生实现***************************/
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
}
// 说明
// [P in keyof T] 等价于 [P in a | b] 等价于 a、b
// T[P] 等价于 ReadOnlyData1[a] 、 ReadOnlyData1[b] 等价于 string、 number
// 最后为 a:string、b:number
// 需要掌握的关键知识 [P in keyof T]的使用
type MyReadonlyTest1 = {
[P in 'a' | 'b'] : string;
}
const d:MyReadonlyTest1 = {
a: "",
b: "",
}
3、Partial
设置接口的所有属性为可写或不可写
interface PartialData1 {
a: string;
b: number;
}
type PartialData2 = Partial<PartialData1> // { a?: string | undefined; b?: string | undefined; }
/********************原生实现***************************/
type MyPartial<T> = {
[P in keyof T]?: T[P] | undefined;
}
type PartialData3 = MyPartial<PartialData1>
4、Pick
设置只获取接口的部分属性
interface PickData1 {
a: string;
b: number;
c: undefined;
}
type PicklData2 = Pick<PickData1, 'a' | 'b'> // { a:string, b:number }
/********************原生实现***************************/
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
}
// 说明
// K extends keyof T 表示 k只能是T的key的子集,也就是说 K 等于 a 或者 a|b 再或者 a|b|c
// 故此在上面的例子中 [p in k] === [p in 'a' | 'b']
type PicklData3 = MyPick<PickData1, 'a' | 'b'>
5、Record
限制对象的keys类型为RecordData1
interface RecordData1 {
a: string;
b: number;
c: undefined;
}
type RecordData2 = Record<'a' | 'b', RecordData1> // { a:RecordData1, b:RecordData1 }
/********************原生实现***************************/
type MyRecord<T extends string | number | symbol, U> = {
[P in T]: U;
}
// 说明
// T extends string | number | symbol , 此时T为联合类型
// 故此在上面的例子中 [p in k] === [p in 'a' | 'b']
type PickData3 = MyRecord<'a' | 'b', RecordData1>
6、Exclude
比较T、U两个泛型,只取T中U所没有的。
type A<T> = T extends string ? number : boolean // 如果T是string,那么就是number类型,否则就是boolean类型
type A1 = A<string> // A1 = A<number>
type A2 = A<string | number> // A2 = A<number | boolean>
// Exclude,代表只能取T独有的属性
type B2 = Exclude<"a" | "b" | "d", "b" | "c"> // B2 = 'a' | 'd'
/******************原生实现,等价于**************/
type B<T, U> = T extends U ? never : T;
type B1 = B<"a" | "b" | "d", "b" | "c"> // B1 = 'a' | 'd'
// 解析
// B<"a" | "b" | "c", "b" | "c"> === B<'a','b' | 'c'> | B<'b','b' | 'c'> | B<'d','b' | 'c'>
7、Extract
比较T、U两个泛型,只取T、U的交集。
type Data4 = {
'a': string
'b': string
}
type Data5 = {
'a': string
'c': string
}
type Data7 = Data4 | Data5
type Data8 = Data4
type Test3 = Extract<Data7,Data4> // Data4
/******************原生实现,等价于**************/
type MyExtract<T, U> = T extends U ? T : never;
type Test4 = MyExtract<Data7,Data4> // Data4
declare编写声明文件
全局文件|对象的声明
背景:
你的html文件里面引用了一个全局的js文件`globalA`,但是当你在使用ts文件引用`globalA`的方法时会报错。
因为你的ts项目并不认识它`globalA`
//globalA.js源代码
function globalA(){}
globalA.version = '1.0.0'
globalA.fn1 = function(){}
解决方法,使用关键字declare
,并且声明一个同名但后缀为.d.ts
的文件
// 在项目里面创建一个globalA.d.ts文件,内容如下
declare function globalA(options: globalA.Options): void;
declare namespace globalA {
const version: string
function fn1(): void
interface Options {
[key: string]: any
}
}
导入对象(module|umd)的声明
背景:
你的项目引用了一个module.exports导出的对象或者第三方包moduleA,这个文件使用js编写的。
但是当你在使用ts文件引用`globalA`的方法时会报错。
因为你的ts项目并不认识它`globalA`
// moduleLib.js文件源码
function moduleLib(options) {
console.log(options)
}
moduleLib.version = '1.9.0';
moduleLib.doSomething = ()=>{
console.log('do')
}
module.exports = moduleLib
// umdLib.js文件源码
((global, factory) => {
//如果 当前的上下文有define函数,并且AMD 说明处于AMD 环境下
if (typeof define === 'function' && define.amd) {
define(factory);
}
else if (typeof exports === 'object') {//commonjs
modules.exports = factory()
}
else {
global.umdLib = factory() //直接挂载成 windows 全局变量
}
})(this, () => {
//本模块的定义
return {
version:'1.0.0',
doSomething(){}
}
})
解决方法,使用关键字declare
,并且声明一个同名但后缀为.d.ts
的文件
// 与moduleLib.js的同一目录下,新建 moduleLib.d.ts 文件,源码如下
declare function moduleLib(options:string):void;
declare namespace moduleLib {
const version:string
function doSomething():void
}
export = moduleLib
// umdLib.js的同一目录下,新建 umdLib.d.ts 文件,源码如下
declare function umdLib(options:string):void;
declare namespace umdLib {
const version:string
function doSomething():void
}
export = umdLib
给第三方库新增自定义方法
import m from "moment"
declare module "moment" {
export function myFunction():void
}
m.myFunction = ()=>{}
dom事件类型声明
使用断言 as
function removeDom(event:Event) {
const target = event.target as HTMLSpanElement;
}
定义时间类型
// 第一种
let a: number;
a = window.setTimeout(function() {}, 0);
// 第二种
const timer: ReturnType<typeof setTimeout> =
setTimeout(() => '', 1000);
第三方变量类型声明方法
declare let process:any;
vsc设置ts中文
常用的类型声明
react
函数组件中的Children
interface Props { children:React.ReactNode, }
window
定时器
let timer:Number = window.setTimeout(()=>{},300)
dom
定义事件类型(React)
ClipboardEvent<T = Element>
剪贴板事件对象DragEvent<T = Element>
拖拽事件对象ChangeEvent<T = Element>
Change 事件对象KeyboardEvent<T = Element>
键盘事件对象MouseEvent<T = Element>
鼠标事件对象TouchEvent<T = Element>
触摸事件对象WheelEvent<T = Element>
滚轮事件对象AnimationEvent<T = Element>
动画事件对象TransitionEvent<T = Element>
过渡事件对象
function onPushInput(e ?:React.MouseEvent){
}
input的更改
input的value的更改需要用state来保存,同时定义onChange事件来时时显示更改的内容。
const [wechat, setWechat] = useState("aaa");
// 函数定义区
function onHandleChange(event:React.ChangeEvent<HTMLInputElement>) {
setWechat(event.target.value)
}
<input
value={wechat}
onChange={onHandleChange}
type="text"
placeholder="填写你的微信号"
ref={inputEle}
/>