JavaScript进阶7
- TypeScript
- Infer
- [Run-time Check运行时类型检查](#Run-time Check运行时类型检查)
- 装饰器
TypeScript
安装Typescript编译器
npm install -g typescript
初始化
tsc -init
关于ts配置项,tsconfig.json
文档解读
typescript
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
......
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
.......
}
声明空间
类型声明空间
typescript
class Foo {}
interface Bar {}
type Bas = {}
let foo:Foo
let bar:Bar
let bas:Bas
变量声明空间
typescript
// 变量声明空间
class Test {}
const a = Test
const b = 2
一些小知识点
导入导出
typescript
//a.ts
export const foo=123
typescript
//b.ts
import { foo } from "./a";
const bar = foo
import { xxx } from 'xxx'
引入的是文件的类型,导出的时候也是按照文件模块/类型引用
global.d.ts
全局模块,是全局直接用
typescript
declare module svg //定义全局类型
再 tsconfig includes注入
基础语法
类型注解
typescript
// type annotation 类型注解
const num :number =123
function sum(a:number,b:number):string{
return a+b.toString()
}
变量类型
基本类型
typescript
// 基本类型
let num:number
let str:string
let bool:boolean //Boolean是构造函数,但是boolean只是类型
num=123
str='abc'
bool=false
// 数组
let numberList:number[]
let strList:Array<string>
let numStr:Array<number|string> // (string|number)[]
numberList=[1,2,3,4]
strList =['1','2','3','4']
numStr = [1,'2',3,'4']
接口
typescript
// 外联接口
interface Person{
name:string,
age?:number //等同于:age:number|undefined,表示age可有可无
}
let person:Person
person={
name:'张三',
age:undefined
}
typescript
// 内联接口
let person:{
name:string,
age:number
}|{sex:string}={
name:"张三",
age:14
}
特殊类型
any undefined void null
typescript
// 特殊类型 any undefined void null
let num:any
let str:string
num=undefined
// strictNullChecks:false 关闭严格检查
// 则 str=undefined 不会报错
function sendMsg(msg:string):void{
console.log(msg);
}
type noop = () =>void //函数声明
泛型
typescript
function reverse<T>(items:T[]):T[]{
let list=[]
for (let i = items.length-1; i >= 0; i--) {
list.push(items[i])
}
return list
}
const a=[1,2,3]
let reverseA=reverse(a)
reverseA=[3]
交叉类型
typescript
// 交叉类型
function a<T extends object,U extends object>(name:T,age:U):T&U{
return {
...name,
...age
}
}
let resultA=a(['张三','李四'],{age:15})
元祖类型
typescript
// 元组类型
let a:[string,number]
a=['张三',15]
type
typescript
// type
type cType=string|number
let c:cType='155'
type和interface的区别
- type是类型的结合,interface是数据结构的描述
- 二者在继承上基本一致,但是写法上是不同的
interface继承:
typescript
interface Shape{
x:number,
y:number
}
interface Recentangle extends Shape{
x:number,
height:number
}
const a:Recentangle={
x:0,
y:10,
height:10
}
typescript
type Shape={
x:number,
y:number
}
type Circle = Shape&{
r:number
}
const c:Circle={
x:10,
y:10,
r:5
}
@types/react
@types/react -> devDependency 16.8
react -> dependencies 16.8
import React from 'react'
@types是约定俗成的
引用的是类型声明包
.d.ts是所有类型的集合,全称是:declaration type 都是通过 @types/react去管理的
typescript
interface Process{
exit(code?:number):void
}
declare var process:Process
process.exit()
或者:
typescript
declare var process:{
exit(code?:number):void
}
process.exit()
以上两种写法,一般都用第一种写法,比较规范,考虑到代码扩展性等
enum枚举
typescript
// 枚举
enum Shape{
circle,
rect,
a,
b,
c
}
const shape=Shape.circle
typescript
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
namespace Weekday {
export function isBusinessDay(day: Weekday) {
switch (day) {
case Weekday.Saturday:
case Weekday.Sunday:
return false;
default:
return true;
}
}
}
const mon = Weekday.Monday
const sun = Weekday.Sunday
console.log(Weekday.isBusinessDay(mon)); // true
console.log(Weekday.isBusinessDay(sun));
函数
函数声明
typescript
interface Foo{
b:string
}
function foo(a:string,c?:number):Foo{
const b="1"
return {
b
}
}
foo('123',123)
foo('345')
函数重载
针对不同场景下参数的兼容,参数不同,则场景不同,考虑到的情况也不一样
类型约束
typescript
// 类型约束 typeof instanceof in
function a(x:number|string){
if(typeof x==='number'){
}
}
interface A{
x:number
}
interface B{
y:string
}
function aa(c:A|B){
if('x' in c){
}
}
Infer
获取函数参数类型
typescript
type ParamType<T> = T extends (arg: infer P) => any ? P : T;
使用:
typescript
type ParamType<T> = T extends (arg: infer P) => any ? P : T;
interface User {
name: string;
age: number;
}
type Func = (user: User) => void;
type Param = ParamType<Func>; // Param = User
type AA = ParamType<string>; // string
const param:Param={
name:'张三',
age:18
}
const aa:AA="111"
console.log(param);
console.log(aa);
ParamType<T>
的定义
typescript
type ParamType<T> = T extends (arg: infer P) => any ? P : T;
这里定义了一个名为 ParamType
的类型别名,它是一个条件类型。条件类型的形式为 T extends U ? X : Y
,表示如果类型 T 可以赋值给类型 U,则结果类型为 X,否则为 Y。
-
(arg: infer P) => any
:这是一个函数类型,其中 infer P 表示推断函数参数的类型。如果T
是一个函数类型,这里会尝试从该函数中推断出参数的类型。 -
P
:如果T
是一个符合上述函数类型的类型(即,如果T
是一个函数),则ParamType<T>
将被解析为该函数的参数类型。 -
T
:如果T
不符合上述函数类型(即,T
不是一个函数类型),ParamType<T>
将直接被解析为T
本身。
Func
和Param
的定义
typescript
interface User {
name: string;
age: number;
}
type Func = (user: User) => void;
type Param = ParamType<Func>; // Param = User
-
User 是一个接口,定义了具有两个属性
name
和age
的对象类型。 -
Func
是一个函数类型,接受一个 User 类型的参数并返回void
。 -
Param
使用ParamType
来推断Func
函数的参数类型。由于Func
是一个接受User
类型参数的函数,因此Param
被解析为User
。
AA
的定义
typescript
type AA = ParamType<string>; // string
-
AA
通过使用ParamType
来处理string
类型。由于string
并不是一个函数类型,因此ParamType<string>
直接解析为string
。总结:
-
ParamType<T>
能够从函数类型中提取参数类型,或直接返回非函数类型的类型。
获取函数返回值
typescript
type ReturnType<T> = T extends (...args: any[]) => infer P ? P : any;
这里同样是一个条件类型的定义,形式为 T extends U ? X : Y
。
-
(...args: any[]) => infer P
:这是一个函数类型,其中...args: any[]
表示函数接受任意数量的任意类型参数,infer P
表示推断函数返回值的类型。 -
P
:如果T
是一个符合上述函数类型的类型(即,如果T
是一个函数类型),则ReturnType<T>
将被解析为该函数的返回值类型。 -
any
:如果T
不符合上述函数类型(即,T
不是一个函数类型),ReturnType<T>
将直接被解析为any
类型。使用:
typescript
// 获取函数返回值
type ReturnTyped<T>=T extends (...args:any[])=>infer P?P:any;
type Func=(numList:number[])=>number[]
type returnFun=ReturnTyped<Func>
type AAFun=ReturnTyped<string>
const ret:returnFun=[1,2,3,4]
const aa:AAFun=1255
const bb:AAFun="12"
const cc:AAFun=[1,'2',4]
console.log("ret",ret);
console.log("aa",aa);
console.log("bb",bb);
console.log("cc",cc);
Run-time Check运行时类型检查
运行时候类型检测 Zod
Zod 既能运行在服务端,也能运行在客户端
typescript
// Run-time check 运行时类型检查
import { z } from "zod";
// creating a schema for strings
const mySchema = z.string();
// parsing
var tuna=mySchema.parse("tuna"); // => "tuna"
console.log(tuna);
// mySchema.parse(12); // => throws ZodError
// "safe" parsing (doesn't throw error if validation fails)
var tunaSafe=mySchema.safeParse("tuna"); // => { success: true; data: "tuna" }
console.log(tunaSafe);
var safe12=mySchema.safeParse(12); // => { success: false; error: ZodError }
console.log(safe12);
运行执行:
tsc --lib es2015 .\04-运行时类型检查.ts
node .\04-运行时类型检查.js
对于对象处理:
typescript
import {z} from 'zod'
const User=z.object({
name:z.string()
})
var obj=User.parse({name:"张三"})
console.log("obj",obj);
type UserMore=z.infer<typeof User>
const user:UserMore={
name:"李四"
}
console.log("user",user);
tsc .\04-运行时类型检查.ts //报错没关系,已经编译成js了
node .\04-运行时类型检查.js
装饰器
tsc --target ES5 --experimentalDecorators
tsconfig.ts
typescript
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
方法装饰
typescript
function foo(){
console.log("foo 开始");
return function(target:Object,propertyKey:string,descriptor:PropertyDescriptor){
console.log("foo 执行");
}
}
function bar(){
console.log("bar 开始");
return function(target:Object,propertyKey:string,descriptor:PropertyDescriptor){
console.log("bar 执行");
}
}
class CType{
@foo()
@bar()
cFunc(){}
}
const c=new CType()
c.cFunc()