cnpm i typescript -g
tsc helloworld.ts
tsc --init
{
"compilerOptions": {
/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. 指定ECMAScript的目标版本*/
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. 指定模块代码的生成方式*/
// "lib": [], /* Specify library files to be included in the compilation. 指定编译的时候用来包含的编译文件*/
// "allowJs": true, /* Allow javascript files to be compiled. 允许编译JS文件*/
// "checkJs": true, /* Report errors in .js files. 在JS中包括错误*/
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. 指定JSX代码的生成方式 是保留还是react-native或者react*/
// "declaration": true, /* Generates corresponding '.d.ts' file.生成相应的类型声明文件 */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. 为每个类型声明文件生成相应的sourcemap*/
// "sourceMap": true, /* Generates corresponding '.map' file. 生成对应的map文件 */
// "outFile": "./", /* Concatenate and emit output to single file. 合并并且把编译后的内容输出 到一个文件里*/
// "outDir": "./", /* Redirect output structure to the directory.按原始结构输出到目标目录 */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. 指定输入文件的根目录,用--outDir来控制输出的目录结构*/
// "composite": true, /* Enable project compilation 启用项目编译*/
// "removeComments": true, /* Do not emit comments to output. 移除注释*/
// "noEmit": true, /* Do not emit outputs. 不要输出*/
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. 当目标是ES5或ES3的时候提供对for-of、扩展运算符和解构赋值中对于迭代器的完整支持*/
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule').r把每一个文件转译成一个单独的模块 */
/* Strict Type-Checking Options */
//"strict": true, /* Enable all strict type-checking options. 启用完全的严格类型检查 */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. 不能使用隐式的any类型*/
// "strictNullChecks": true, /* Enable strict null checks. 启用严格的NULL检查*/
// "strictFunctionTypes": true, /* Enable strict checking of function types. 启用严格的函数类型检查*/
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions.启用函数上严格的bind call 和apply方法 */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. 启用类上初始化属性检查*/
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type.在默认的any中调用 this表达式报错 */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. 在严格模式下解析并且向每个源文件中发射use strict*/
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. 有未使用到的本地变量时报错 */
// "noUnusedParameters": true, /* Report errors on unused parameters. 有未使用到的参数时报错*/
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. 当不是所有的代码路径都有返回值的时候报错*/
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. 在switch表达式中没有替代的case会报错 */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). 指定模块的解析策略 node classic*/
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. 在解析非绝对路径模块名的时候的基准路径*/
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. 一些路径的集合*/
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. 根目录的列表,在运行时用来合并内容*/
// "typeRoots": [], /* List of folders to include type definitions from. 用来包含类型声明的文件夹列表*/
// "types": [], /* Type declaration files to be included in compilation.在编译的时候被包含的类型声明 */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking.当没有默认导出的时候允许默认导入,这个在代码执行的时候没有作用,只是在类型检查的时候生效 */
//"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.*/
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks.不要symlinks解析的真正路径 */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. 指定ts文件位置*/
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. 指定 map文件存放的位置 */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. 源文件和sourcemap 文件在同一文件中,而不是把map文件放在一个单独的文件里*/
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. 源文件和sourcemap 文件在同一文件中*/
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. 启动装饰器*/
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
}
}
tsc
let married: boolean=false;
let age: number=10;
let firstname: string='zfpx';
let arr2: number[]=[4,5,6];
let arr3: Array<number>=[7,8,9];
数量
和类型
的数组let zhufeng:[string,number] = ['zhufeng',5];
zhufeng[0].length;
zhufeng[1].toFixed(2);
元组 | 数组 |
---|---|
每一项可以是不同的类型 | 每一项都是同一种类型 |
有预定义的长度 | 没有长度限制 |
用于表示一个固定的结构 | 用于表示一个列表 |
const animal:[string,number,boolean] = ['zhufeng',10,true];
enum Gender{
GIRL,
BOY
}
console.log(`李雷是${Gender.BOY}`);
console.log(`韩梅梅是${Gender.GIRL}`);
enum Week{
MONDAY=1,
TUESDAY=2
}
console.log(`今天是星期${Week.MONDAY}`);
const enum Colors {
Red,
Yellow,
Blue
}
let myColors = [Colors.Red, Colors.Yellow, Colors.Blue];
const enum Color {Red, Yellow, Blue = "blue".length};
any
就是可以赋值给任意类型any
let root:any=document.getElementById('root');
root.style.color='red';
let root:(HTMLElement|null)=document.getElementById('root');
root!.style.color='red';//非空断言操作符
strictNullChecks
参数用于新的严格空检查模式,在严格空检查模式下, null 和 undefined 值都不属于任何一个类型,它们只能赋值给自己这种类型或者 anylet x: number;
x = 1;
x = undefined;
x = null;
let y: number | null | undefined;
y = 1;
y = undefined;
y = null;
function greeting(name:string):void {
console.log('hello',name);
//当我们声明一个变量类型是 void 的时候,它的非严格模式(strictNullChecks:false)下仅可以被赋值为 null 和 undefined
//严格模式(strictNullChecks:true)下只能返回undefined
//return null;
//return undefined;
}
never是其它类型(null undefined)的子类型,代表不会出现的值
// 返回never的函数 必须存在 无法达到( unreachable ) 的终点
function error(message: string): never {
throw new Error(message);
}
let result1 = error('hello');
// 由类型推论得到返回值为 never
function fail() {
return error("Something failed");
}
let result = fail();
// 返回never的函数 必须存在 无法达到( unreachable ) 的终点
function infiniteLoop(): never {
while (true) {}
}
// Compiled with --strictNullChecks
function fn(x: number | string) {
if (typeof x === 'number') {
// x: number 类型
} else if (typeof x === 'string') {
// x: string 类型
} else {
// x: never 类型
// --strictNullChecks 模式下,这里的代码将不会被执行,x 无法被观察
}
}
const sym1 = Symbol('key');
const sym2 = Symbol('key');
Symbol('key') === Symbol('key') // false
BigInt
的时候,必须添加 ESNext
的编译辅助库1n
需要 "target": "ESNext"
const max = Number.MAX_SAFE_INTEGER;// 2**53-1
console.log(max + 1 === max + 2);
const max = BigInt(Number.MAX_SAFE_INTEGER);
console.log(max + 1n === max + 2n);
let foo: number;
let bar: bigint;
foo =bar;
bar = foo;
let username2;
username2 = 10;
username2 = 'zhufeng';
username2 = null;
let name = 'zhufeng';
console.log(name.toUpperCase());
console.log((new String('zhufeng')).toUpperCase());
let isOK: boolean = true; // 编译通过
let isOK: boolean = Boolean(1) // 编译通过
let isOK: boolean = new Boolean(1); // 编译失败 期望的 isOK 是一个原始数据类型
let name: string | number;
console.log(name.toString());
name = 3;
console.log(name.toFixed(2));
name = 'zhufeng';
console.log(name.length);
export {};
let name: string | number;
console.log((name as string).length);
console.log((name as number).toFixed(2));
console.log((name as boolean));
双重断言
interface Person {
name: string;
age: number;
}
const person = 'zhufeng' as any as Person; // ok
const up:'Up'= 'Up';
const down: "Down" = "Down";
const left: "Left" = "Left";
const right: "Right" = "Right";
type Direction = 'Up' | 'Down' | 'Left' | 'Right';
function move(direction: Direction) {}
move("Up");
type Person = {
name:string,
age:number
};
几个字符串
中的一个, 联合类型(Union Types)表示取值可以为多种类型
中的一种function hello(name:string):void {
console.log('hello',name);
}
hello('zfpx');
type GetUsernameFunction = (x:string,y:string)=>string;
let getUsername:GetUsernameFunction = function(firstName,lastName){
return firstName + lastName;
}
let hello2 = function (name:string):void {
console.log('hello2',name);
return undefined;
}
hello2('zhufeng');
在TS中函数的形参和实参必须一样,不一样就要配置可选参数,而且必须是最后一个参数
function print(name:string,age?:number):void {
console.log(name,age);
}
print('zfpx');
function ajax(url:string,method:string='GET') {
console.log(url,method);
}
ajax('/users');
function sum(...numbers:number[]) {
return numbers.reduce((val,item)=>val+=item,0);
}
console.log(sum(1,2,3));
let obj: any={};
function attr(val: string): void;
function attr(val: number): void;
function attr(val:any):void {
if (typeof val === 'string') {
obj.name=val;
} else {
obj.age=val;
}
}
attr('zfpx');
attr(9);
attr(true);
console.log(obj);
class Person{
name:string;
getName():void{
console.log(this.name);
}
}
let p1 = new Person();
p1.name = 'zhufeng';
p1.getName();
/**
* 当我们写一个类的时候,会得到2个类型
* 1. 构造函数类型的函数类型
* 2. 类的实例类型
*/
class Component {
static myName: string = '静态名称属性';
myName: string = '实例名称属性';
}
let com = Component;
//Component类名本身表示的是实例的类型
//ts 一个类型 一个叫值
//冒号后面的是类型
//放在=后面的是值
let c: Component = new Component();
let f: typeof Component = com;
class User {
myname:string;
constructor(myname: string) {
this.myname = myname;
}
get name() {
return this.myname;
}
set name(value) {
this.myname = value;
}
}
let user = new User('zhufeng');
user.name = 'jiagou';
console.log(user.name);
"use strict";
var User = /** @class */ (function () {
function User(myname) {
this.myname = myname;
}
Object.defineProperty(User.prototype, "name", {
get: function () {
return this.myname;
},
set: function (value) {
this.myname = value;
},
enumerable: true,
configurable: true
});
return User;
}());
var user = new User('zhufeng');
user.name = 'jiagou';
console.log(user.name);
class User {
constructor(public myname: string) {}
get name() {
return this.myname;
}
set name(value) {
this.myname = value;
}
}
let user = new User('zhufeng');
console.log(user.name);
user.name = 'jiagou';
console.log(user.name);
构造函数
中初始化常量
标志符,其值不能被重新分配编译
阶段进行代码检查。而 const 则会在运行时
检查(在支持 const 语法的 JavaScript 运行时环境中)class Animal {
public readonly name: string
constructor(name:string) {
this.name = name;
}
changeName(name:string){
this.name = name;
}
}
let a = new Animal('zhufeng');
a.changeName('jiagou');
class Person {
name: string;//定义实例的属性,默认省略public修饰符
age: number;
constructor(name:string,age:number) {//构造函数
this.name=name;
this.age=age;
}
getName():string {
return this.name;
}
setName(name:string): void{
this.name=name;
}
}
class Student extends Person{
no: number;
constructor(name:string,age:number,no:number) {
super(name,age);
this.no=no;
}
getNo():number {
return this.no;
}
}
let s1=new Student('zfpx',10,1);
console.log(s1);
class Father {
public name: string; //类里面 子类 其它任何地方外边都可以访问
protected age: number; //类里面 子类 都可以访问,其它任何地方不能访问
private money: number; //类里面可以访问, 子类和其它任何地方都不可以访问
constructor(name:string,age:number,money:number) {//构造函数
this.name=name;
this.age=age;
this.money=money;
}
getName():string {
return this.name;
}
setName(name:string): void{
this.name=name;
}
}
class Child extends Father{
constructor(name:string,age:number,money:number) {
super(name,age,money);
}
desc() {
console.log(`${this.name} ${this.age} ${this.money}`);
}
}
let child = new Child('zfpx',10,1000);
console.log(child.name);
console.log(child.age);
console.log(child.money);
class Father {
static className='Father';
static getClassName() {
return Father.className;
}
public name: string;
constructor(name:string) {//构造函数
this.name=name;
}
}
console.log(Father.className);
console.log(Father.getClassName());
class Person{
say() {
console.log('hello')
}
}
function Person() {}
Object.defineProperty(Person.prototype, 'say', {
value: function() { console.log('hello'); },
enumerable: false,
configurable: true,
writable: true
});
namespace a {
//当装饰器作为修饰类的时候,会把构造器传递进去
function addNameEat(constructor: Function) {
constructor.prototype.name = "zhufeng";
constructor.prototype.eat = function () {
console.log("eat");
};
}
@addNameEat
class Person {
name!: string;
eat!: Function;
constructor() {}
}
let p: Person = new Person();
console.log(p.name);
p.eat();
}
namespace b {
//还可以使用装饰器工厂
function addNameEatFactory(name:string) {
return function (constructor: Function) {
constructor.prototype.name = name;
constructor.prototype.eat = function () {
console.log("eat");
};
};
}
@addNameEatFactory('zhufeng')
class Person {
name!: string;
eat!: Function;
constructor() {}}
let p: Person = new Person();
console.log(p.name);
p.eat();
}
namespace c {
//还可以替换类,不过替换的类要与原类结构相同
function enhancer(constructor: Function) {
return class {
name: string = "jiagou";
eat() {
console.log("吃饭饭");
}
};
}
@enhancer
class Person {
name!: string;
eat!: Function;
constructor() {}}
let p: Person = new Person();
console.log(p.name);
p.eat();
}
namespace d {
//修饰实例属性
function upperCase(target: any, propertyKey: string) {
let value = target[propertyKey];
const getter = function () {
return value;
}
// 用来替换的setter
const setter = function (newVal: string) {
value = newVal.toUpperCase()
};
// 替换属性,先删除原先的属性,再重新定义属性
if (delete target[propertyKey]) {
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
}
//修饰实例方法
function noEnumerable(target: any, property: string, descriptor: PropertyDescriptor) {
console.log('target.getName', target.getName);
console.log('target.getAge', target.getAge);
descriptor.enumerable = true;
}
//重写方法
function toNumber(target: any, methodName: string, descriptor: PropertyDescriptor) {
let oldMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
args = args.map(item => parseFloat(item));
return oldMethod.apply(this, args);
}
}
class Person {
@upperCase
name: string = 'zhufeng'
public static age: number = 10
constructor() { }
@noEnumerable
getName() {
console.log(this.name);
}
@toNumber
sum(...args: any[]) {
return args.reduce((accu: number, item: number) => accu + item, 0);
}
}
let p: Person = new Person();
for (let attr in p) {
console.log('attr=', attr);
}
p.name = 'jiagou';
p.getName();
console.log(p.sum("1", "2", "3"));
}
namespace d {
interface Person {
age: number;
}
function addAge(target: any, methodName: string, paramsIndex: number) {
console.log(target);
console.log(methodName);
console.log(paramsIndex);
target.age = 10;
}
class Person {
login(username: string, @addAge password: string) {
console.log(this.age, username, password);
}
}
let p = new Person();
p.login('zhufeng', '123456')
}
namespace e {
function Class1Decorator() {
return function (target: any) {
console.log("类1装饰器");
}
}
function Class2Decorator() {
return function (target: any) {
console.log("类2装饰器");
}
}
function MethodDecorator() {
return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
console.log("方法装饰器");
}
}
function Param1Decorator() {
return function (target: any, methodName: string, paramIndex: number) {
console.log("参数1装饰器");
}
}
function Param2Decorator() {
return function (target: any, methodName: string, paramIndex: number) {
console.log("参数2装饰器");
}
}
function PropertyDecorator(name: string) {
return function (target: any, propertyName: string) {
console.log(name + "属性装饰器");
}
}
@Class1Decorator()
@Class2Decorator()
class Person {
@PropertyDecorator('name')
name: string = 'zhufeng';
@PropertyDecorator('age')
age: number = 10;
@MethodDecorator()
greet(@Param1Decorator() p1: string, @Param2Decorator() p2: string) { }
}
}
/**
name属性装饰器
age属性装饰器
参数2装饰器
参数1装饰器
方法装饰器
类2装饰器
类1装饰器
*/
abstract class Animal {
name!:string;
abstract speak():void;
}
class Cat extends Animal{
speak(){
console.log('喵喵喵');
}
}
let animal = new Animal();//Cannot create an instance of an abstract class
animal.speak();
let cat = new Cat();
cat.speak();
访问控制修饰符 | private protected public |
---|---|
只读属性 | readonly |
静态属性 | static |
抽象类、抽象方法 | abstract |
abstract class Animal{
abstract speak():void;
}
class Dog extends Animal{
speak(){
console.log('小狗汪汪汪');
}
}
class Cat extends Animal{
speak(){
console.log('小猫喵喵喵');
}
}
let dog=new Dog();
let cat=new Cat();
dog.speak();
cat.speak();
class Animal{
speak(word:string):string{
return '动作叫:'+word;
}
}
class Cat extends Animal{
speak(word:string):string{
return '猫叫:'+word;
}
}
let cat = new Cat();
console.log(cat.speak('hello'));
//--------------------------------------------
function double(val:number):number
function double(val:string):string
function double(val:any):any{
if(typeof val == 'number'){
return val *2;
}
return val + val;
}
let r = double(1);
console.log(r);
class Animal{
speak(word:string):string{
return 'Animal: '+word;
}
}
class Cat extends Animal{
speak(word:string):string{
return 'Cat:'+word;
}
}
class Dog extends Animal{
speak(word:string):string{
return 'Dog:'+word;
}
}
let cat = new Cat();
console.log(cat.speak('hello'));
let dog = new Dog();
console.log(dog.speak('hello'));
行为的抽象
,另外可以用来描述对象的形状
//接口可以用来描述`对象的形状`,少属性或者多属性都会报错
interface Speakable{
speak():void;
name?:string;//?表示可选属性
}
let speakman:Speakable = {
speak(){},//少属性会报错
name,
age//多属性也会报错
}
//接口可以在面向对象编程中表示为行为的抽象
interface Speakable{
speak():void;
}
interface Eatable{
eat():void
}
//一个类可以实现多个接口
class Person implements Speakable,Eatable{
speak(){
console.log('Person说话');
}
eat(){}
}
class TangDuck implements Speakable{
speak(){
console.log('TangDuck说话');
}
eat(){}
}
//无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]:any`,propName名字是任意的
interface Person {
readonly id: number;
name: string;
[propName: string]: any;
}
let p1 = {
id:1,
name:'zhufeng',
age:10
}
interface Speakable {
speak(): void
}
interface SpeakChinese extends Speakable {
speakChinese(): void
}
class Person implements SpeakChinese {
speak() {
console.log('Person')
}
speakChinese() {
console.log('speakChinese')
}
}
interface Person{
readonly id:number;
name:string
}
let tom:Person = {
id :1,
name:'zhufeng'
}
tom.id = 1;
interface discount{
(price:number):number
}
let cost:discount = function(price:number):number{
return price * .8;
}
index
的类型是 number,那么值的类型必须是 stringindex
的类型是 string,那么值的类型必须是 stringinterface UserInterface {
[index:number]:string
}
let arr:UserInterface = ['zfpx1','zfpx2'];
console.log(arr);
interface UserInterface2 {
[index:string]:string
}
let obj:UserInterface2 = {name:'zhufeng'};
interface Speakable {
name: string;
speak(words: string): void
}
class Dog implements Speakable {
name!: string;
speak(words:string) {
console.log(words);
}
}
let dog = new Dog();
dog.speak('汪汪汪');
class Animal{
constructor(public name:string){
}
}
//不加new是修饰函数的,加new是修饰类的
interface WithNameClass{
new(name:string):Animal
}
function createAnimal(clazz:WithNameClass,name:string){
return new clazz(name);
}
let a = createAnimal(Animal,'zhufeng');
console.log(a.name);
abstract class Animal{
name:string;
constructor(name:string){
this.name = name;
}
abstract speak():void;
}
interface Flying{
fly():void
}
class Duck extends Animal implements Flying{
speak(){
console.log('汪汪汪');
}
fly(){
console.log('我会飞');
}
}
let duck = new Duck('zhufeng');
duck.speak();
duck.fly();
T
作用域只限于函数内部使用function createArray(length: number, value: any): Array<any> {
let result: any = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray(3,'x');
console.log(result);
使用了泛型
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray2<string>(3,'x');
console.log(result);
arguments
function sum() {
let args: IArguments = arguments;
for (let i = 0; i < args.length; i++) {
console.log(args[i]);
}
}
sum(1, 2, 3);
let root = document.getElementById('root');
let children: HTMLCollection = (root as HTMLElement).children;
children.length;
let nodeList: NodeList = (root as HTMLElement).childNodes;
nodeList.length;
class MyArray<T>{
private list:T[]=[];
add(value:T) {
this.list.push(value);
}
getMax():T {
let result=this.list[0];
for (let i=0;i<this.list.length;i++){
if (this.list[i]>result) {
result=this.list[i];
}
}
return result;
}
}
let arr=new MyArray();
arr.add(1); arr.add(2); arr.add(3);
let ret = arr.getMax();
console.log(ret);
function factory<T>(type: {new():T}): T {
return new type(); // This expression is not constructable.
}
interface Calculate{
<T>(a:T,b:T):T
}
let add:Calculate = function<T>(a:T,b:T){
return a;
}
add<number>(1,2);
function swap<A,B>(tuple:[A,B]):[B,A]{
return [tuple[1],tuple[0]];
}
let swapped = swap<string,number>(['a',1]);
console.log(swapped);
console.log(swapped[0].toFixed(2));
console.log(swapped[1].length);
function createArray3<T=number>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result2 = createArray3(3,'x');
console.log(result2);
function logger<T>(val: T) {
console.log(val.length); //直接访问会报错
}
//可以让泛型继承一个接口
interface LengthWise {
length: number
}
//可以让泛型继承一个接口
function logger2<T extends LengthWise>(val: T) {
console.log(val.length)
}
logger2('zhufeng');
logger2(1);
interface Cart<T>{
list:T[]
}
let cart:Cart<{name:string,price:number}> = {
list:[{name:'zhufeng',price:10}]
}
console.log(cart.list[0].name,cart.list[0].price);
import compose from ".";
/* zero functions */
console.log(compose()<string>("zhufeng"));
/* one functions */
interface F{
(a:string):string
}
let f: F = (a:string):string=>a+'f';
console.log(compose<F>(f)("zhufeng"));
/* two functions */
type A = string;
type R = string;
type T = string[];
let f1 = (a: A): R => a + "f1";
let f2 = (...a: T): A => a + "f2";
console.log(compose<A,T,R>(f1,f2)("zhufeng"));
type Cart<T> = {list:T[]} | T[];
let c1:Cart<string> = {list:['1']};
let c2:Cart<number> = [1];
Duck-Check
,就是说只要目标类型中声明的属性变量在源类型中都存在就是兼容的interface Animal {
name: string;
age: number;
}
interface Person {
name: string;
age: number;
gender: number
}
// 要判断目标类型`Person`是否能够兼容输入的源类型`Animal`
function getName(animal: Animal): string {
return animal.name;
}
let p = {
name: 'zhufeng',
age: 10,
gender: 0
}
getName(p);
//只有在传参的时候两个变量之间才会进行兼容性的比较,赋值的时候并不会比较,会直接报错
let a: Animal = {
name: 'zhufeng',
age: 10,
gender: 0
}
//基本数据类型也有兼容性判断
let num : string|number;
let str:string='zhufeng';
num = str;
//只要有toString()方法就可以赋给字符串变量
let num2 : {
toString():string
}
let str2:string='jiagou';
num2 = str2;
class Animal{
name:string
}
class Bird extends Animal{
swing:number
}
let a:Animal;
a = new Bird();
let b:Bird;
//并不是父类兼容子类,子类不兼容父类
b = new Animal();
class Animal{
name:string
}
//如果父类和子类结构一样,也可以的
class Bird extends Animal{}
let a:Animal;
a = new Bird();
let b:Bird;
b = new Animal();
//甚至没有关系的两个类的实例也是可以的
class Animal{
name:string
}
class Bird{
name:string
}
let a:Animal ;
a = new Bird();
let b:Bird;
b = new Animal();
type sumFunc = (a:number,b:number)=>number;
let sum:sumFunc;
function f1(a:number,b:number):number{
return a+b;
}
sum = f1;
//可以省略一个参数
function f2(a:number):number{
return a;
}
sum = f2;
//可以省略二个参数
function f3():number{
return 0;
}
sum = f3;
//多一个参数可不行
function f4(a:number,b:number,c:number){
return a+b+c;
}
sum = f4;
type GetPerson = ()=>{name:string,age:number};
let getPerson:GetPerson;
//返回值一样可以
function g1(){
return {name:'zhufeng',age:10};
}
getPerson = g1;
//返回值多一个属性也可以
function g2(){
return {name:'zhufeng',age:10,gender:'male'};
}
getPerson = g2;
//返回值少一个属性可不行
function g3(){
return {name:'zhufeng'};
}
getPerson = g3;
//因为有可能要调用返回值上的方法
getPerson().age.toFixed();
不变(Invariant):如果类型不完全相同,则它们是不兼容的。
A ≼ B 意味着 A 是 B 的子类型。
x : A 意味着 x 的类型为 A
返回值类型是协变的,而参数类型是逆变的
class Animal{}
class Dog extends Animal{
public name:string = 'Dog'
}
class BlackDog extends Dog {
public age: number = 10
}
class WhiteDog extends Dog {
public home: string = '北京'
}
let animal: Animal;
let blackDog: BlackDog;
let whiteDog: WhiteDog;
type Callback = (dog: Dog)=>Dog;
function exec(callback:Callback):void{
callback(whiteDog);
}
//不行 callback(redDog);
type ChildToChild = (blackDog: BlackDog) => BlackDog;
const childToChild: ChildToChild = (blackDog: BlackDog): BlackDog => blackDog
exec(childToChild);
//也不行,理由同上
type ChildToParent = (blackDog: BlackDog) => Animal;
const childToParent: ChildToParent = (blackDog: BlackDog): Animal => animal
exec(childToParent);
//不行 因为有可能调用返回的Dog的方法
type ParentToParent = (animal: Animal) => Animal;
const parentToParent: ParentToParent = (animal: Animal): Animal => animal
exec(parentToParent);
//可以,所有的狗都是动物,返回的不管什么狗都是狗
type ParentToChild = (animal: Animal) => BlackDog;
const parentToChild: ParentToChild = (animal: Animal): BlackDog => blackDog
exec(parentToChild);
//(Animal → Greyhound) ≼ (Dog → Dog)
//返回值类型很容易理解:黑狗是狗的子类。但参数类型则是相反的:动物是狗的父类!
// string | number|boolean 是 string | number的父类型
// string是string|number的子类型
type Callback2 = (a: string | number) => string | number;
function exec2(callback: Callback2):void{
callback('');
}
type ParentToChild2 = (a: string | number | boolean) => string;
const parentToChild2: ParentToChild2 = (a: string | number | boolean): string => ''
exec2(parentToChild2);
type Callback3 = (a: string | number) => string | number;
function exec3(callback: Callback2): void {
callback('');
}
type ParentToParent3 = (a: string) => string;
const parentToParent3: ParentToParent3 = (a: string): string => ''
exec3(parentToChild3);
--strictFunctionTypes
或 --strict
标记来修复这个问题//接口内容为空没用到泛型的时候是可以的
//1.接口内容为空没用到泛型的时候是可以的
interface Empty<T>{}
let x!:Empty<string>;
let y!:Empty<number>;
x = y;
//2.接口内容不为空的时候不可以
interface NotEmpty<T>{
data:T
}
let x1!:NotEmpty<string>;
let y1!:NotEmpty<number>;
x1 = y1;
//实现原理如下,称判断具体的类型再判断兼容性
interface NotEmptyString{
data:string
}
interface NotEmptyNumber{
data:number
}
let xx2!:NotEmptyString;
let yy2!:NotEmptyNumber;
xx2 = yy2;
//数字可以赋给枚举
enum Colors {Red,Yellow}
let c:Colors;
c = Colors.Red;
c = 1;
c = '1';
//枚举值可以赋给数字
let n:number;
n = 1;
n = Colors.Red;
function double(input: string | number | boolean) {
if (typeof input === 'string') {
return input + input;
} else {
if (typeof input === 'number') {
return input * 2;
} else {
return !input;
}
}
}
class Animal {
name!: string;
}
class Bird extends Animal {
swing!: number
}
function getName(animal: Animal) {
if (animal instanceof Bird) {
console.log(animal.swing);
} else {
console.log(animal.name);
}
}
strictNullChecks
选项,那么对于可能为null的变量不能调用它上面的方法和属性function getFirstLetter(s: string | null) {
//第一种方式是加上null判断
if (s == null) {
return '';
}
//第二种处理是增加一个或的处理
s = s || '';
return s.charAt(0);
}
//它并不能处理一些复杂的判断,需要加非空断言操作符
function getFirstLetter2(s: string | null) {
function log() {
console.log(s!.trim());
}
s = s || '';
log();
return s.charAt(0);
}
a?.b; //如果a是null/undefined,那么返回undefined,否则返回a.b的值.
a == null ? undefined : a.b;
a?.[x]; //如果a是null/undefined,那么返回undefined,否则返回a[x]的值
a == null ? undefined : a[x];
a?.b(); // 如果a是null/undefined,那么返回undefined
a == null ? undefined : a.b(); //如果a.b不函数的话抛类型错误异常,否则计算a.b()的结果
a?.(); //如果a是null/undefined,那么返回undefined
a == null ? undefined : a(); //如果A不是函数会抛出类型错误
//否则 调用a这个函数
链判断运算符 还处于 stage1 阶段,TS 也暂时不支持
interface WarningButton{
class:'warning',
text1:'修改'
}
interface DangerButton{
class:'danger',
text2:'删除'
}
type Button = WarningButton|DangerButton;
function getButton(button:Button){
if(button.class=='warning'){
console.log(button.text1);
}
if(button.class=='danger'){
console.log(button.text2);
}
}
类型字面量+可辨识联合类型
interface User {
username: string
}
type Action = {
type:'add',
payload:User
} | {
type: 'delete'
payload: number
}
const UserReducer = (action: Action) => {
switch (action.type) {
case "add":
let user: User = action.payload;
break;
case "delete":
let id: number = action.payload;
break;
default:
break;
}
};
interface Bird {
swing: number;
}
interface Dog {
leg: number;
}
function getNumber(x: Bird | Dog) {
if ("swing" in x) {
return x.swing;
}
return x.leg;
}
type is Type1Class
就是类型谓词parameterName is Type
这种形式,parameterName
必须是来自于当前函数签名里的一个参数名isType1
时,如果原始类型兼容,TypeScript
会将该变量缩小到该特定类型function isType1(type: Type1Class | Type2Class): type is Type1Class {
return (<Type1Class>type).func1 !== undefined;
}
interface Bird {
swing: number;
}
interface Dog {
leg: number;
}
//没有相同字段可以定义一个类型保护函数
function isBird(x:Bird|Dog): x is Bird{
return (<Bird>x).swing == 2;
//return (x as Bird).swing == 2;
}
function getAnimal(x: Bird | Dog) {
if (isBird(x)) {
return x.swing;
}
return x.leg;
}
let value: any;
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
let value: any;
value.foo.bar; // OK
value.trim(); // OK
value(); // OK
new value(); // OK
就像所有类型都可以被归为 any,所有类型也都可以被归为 unknown。这使得 unknown 成为 TypeScript 类型系统的另一种顶级类型(另一种是 any)
任何类型都可以赋值给unknown
类型
let value: unknown;
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
unknown
类型只能被赋值给any
类型和unknown
类型本身let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error
unknown
上面进行任何操作const value: unknown = "Hello World";
const someString: string = value as string;
type UnionType1 = unknown | null; // unknown
type UnionType2 = unknown | undefined; // unknown
type UnionType3 = unknown | string; // unknown
type UnionType4 = unknown | number[]; // unknown
type IntersectionType1 = unknown & null; // null
type IntersectionType2 = unknown & undefined; // undefined
type IntersectionType3 = unknown & string; // string
type IntersectionType4 = unknown & number[]; // number[]
type IntersectionType5 = unknown & any; // any
type isNever = never extends unknown ? true : false;
type key = keyof unknown;
un1===un2;
un1!==un2;
un1 += un2;
un.name
un();
new un();
type getType<T> = {
[P in keyof T]:number
}
type t = getType<unknown>;
let foo = 1; // foo 是 'number'
let bar = 'zhufeng'; // bar 是 'string'
//foo = bar; // Error: 不能将 'string' 赋值给 `number`
return
语句推断function add(a: number, b: number) {
return a + b;
}
let c = add(1,2);
type Sum = (a: number, b: number) => number;
let sum: Sum = (a, b) => {
a='zhufeng';
return a + b;
};
const person = {
name: 'zhufeng',
age: 11
};
let name =person.name;
let age =person.age;
age = 'hello'; // Error:不能把 'string' 类型赋值给 'number' 类型
const person = {
name: 'zhufeng',
age: 11
};
let { name,age } = person;
age = 'hello'; // Error:不能把 'string' 类型赋值给 'number' 类型
//数组也一样
const numbers = [1, 2, 3];
numbers[0] = 'hello'; // Error:不能把 'string' 类型赋值给 'number' 类型
interface DefaultProps{
name?:string;
age?:number;
}
let defaultProps: DefaultProps = {
name:'zhufeng',
age:10
}
let props = {
...defaultProps,
home:'北京'
}
type Props = typeof props;
function addOne(a:any) {
return a + 1;
}
function sum(a: number, b: number) {
return a + addOne(b);
}
type Ret = ReturnType<typeof sum>;
//TypeScript 交叉类型是将多个类型合并为一个类型
//这让我们可以把现有的多种类型叠加到一起成为一种类型
//它包含了所需的所有类型的特性
export {}
//接口的交叉
interface Bird {
name: string,
fly(): void
}
interface Person {
name: string,
talk(): void
}
type BirdPerson = Bird & Person;
let p: BirdPerson = { name: 'zhufeng', fly() { }, talk() { } };
p.fly;
p.name
p.talk;
interface X {
a: string;
b: string;
}
interface Y {
a: number;
c: string
}
type XY = X & Y;
type YX = Y & X;
//c = string & number
//let p1: XY={a:'',b:'',c:''};
联合类型的交叉类型
type Ta = string | number;
type Tb = number | boolean;
type Tc = Ta & Tb;
mixin
混入模式可以让你从两个对象中创建一个新对象,新对象会拥有着两个对象所有的功能
interface AnyObject {
[prop: string]: any;
}
function mixin<T extends AnyObject, U extends AnyObject>(one: T,two: U): T & U {
const result = <T & U>{};
for (let key in one) {
(<T>result)[key] = one[key];
}
for (let key in two) {
(<U>result)[key] = two[key];
}
return result;
}
const x = mixin({ name: "zhufeng" }, { age: 11 });
console.log(x.name, x.age);
//先定义类型,再定义变量
type People = {
name:string,
age:number,
gender:string
}
let p1:People = {
name:'zhufeng',
age:10,
gender:'male'
}
//先定义变量,再定义类型
let p1 = {
name:'zhufeng',
age:10,
gender:'male'
}
type People = typeof p1;
function getName(p:People):string{
return p.name;
}
getName(p1);
interface Person{
name:string;
age:number;
job:{
name:string
};
interests:{name:string,level:number}[]
}
let FrontEndJob:Person['job'] = {
name:'前端工程师'
}
let interestLevel:Person['interests'][0]['level'] = 2;
interface Person{
name:string;
age:number;
gender:'male'|'female';
}
//type PersonKey = 'name'|'age'|'gender';
type PersonKey = keyof Person;
function getValueByKey(p:Person,key:PersonKey){
return p[key];
}
let val = getValueByKey({name:'zhufeng',age:10,gender:'male'},'name');
console.log(val);
interface Person{
name:string;
age:number;
gender:'male'|'female';
}
//批量把一个接口中的属性都变成可选的
type PartPerson = {
[Key in keyof Person]?:Person[Key]
}
let p1:PartPerson={};
//也可以使用泛型
type Part<T> = {
[key in keyof T]?:T[key]
}
let p2:Part<Person>={};
function pick<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map((n) => o[n]);
}
let user = { id: 1, name: 'zhufeng' };
type User = typeof user;
const res = pick<User, keyof User>(user, ["id", "name"]);
console.log(res);
interface Fish {
name: string
}
interface Water {
name: string
}
interface Bird {
name: string
}
interface Sky {
name: string
}
//若 T 能够赋值给 Fish,那么类型是 Water,否则为 Sky
type Condition<T> = T extends Fish ? Water : Sky;
let condition: Condition<Fish> = { name: '水' };
interface Fish {
fish: string
}
interface Water {
water: string
}
interface Bird {
bird: string
}
interface Sky {
sky: string
}
//naked type
type Condition<T> = T extends Fish ? Water : Sky;
//(Fish extends Fish ? Water : Sky) | (Bird extends Fish ? Water : Sky)
// Water|Sky
let condition1: Condition<Fish | Bird> = { water: '水' };
let condition2: Condition<Fish | Bird> = { sky: '天空' };
//none naked type
//type Condition<T> = [T] extends [Fish] ? Water : Sky;
//never会被自动过滤
type Diff<T, U> = T extends U ? never : T;
type R = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"
type Filter<T, U> = T extends U ? T : never;
type R1 = Filter<string | number | boolean, number>;
type Exclude<T, U> = T extends U ? never : T;
type E = Exclude<string|number,string>;
let e:E = 10;
type Extract<T, U> = T extends U ? T : never;
type E = Extract<string|number,string>;
let e:E = '1';
type NonNullable<T> = T extends null | undefined ? never : T;
type E = NonNullable<string|number|null|undefined>;
let e:E = null;
export {}
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
function getUserInfo() {
return { name: "zhufeng", age: 10 };
}
// 通过 ReturnType 将 getUserInfo 的返回值类型赋给了 UserInfo
type UserInfo = ReturnType<typeof getUserInfo>;
const userA: UserInfo = {
name: "zhufeng",
age: 10
};
export {}
type Parameters<T> = T extends (...args: infer R) => any ? R : any;
type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<(<T>(arg: T) => T)>; // [unknown]
type Constructor = new (...args: any[]) => any;
type ConstructorParameters<T extends Constructor> = T extends new (...args: infer P) => any ? P : never;
type InstanceType<T extends Constructor> = T extends new (...args: any[]) => infer R ? R : any;
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
getName() { console.log(this.name) }
}
//构造函数参数
type constructorParameters = ConstructorParameters<typeof Person>;
let params: constructorParameters = ['zhufeng']
//实例类型
type Instance = InstanceType<typeof Person>;
let instance: Instance = { name: 'zhufeng', getName() { } };
利用在逆变位置上,同一类型变量的多个候选类型将会被推断为交叉类型的特性
tuple转union
type ElementOf<T> = T extends Array<infer E> ? E : never;
type TTuple = [string, number];
type ToUnion = ElementOf<TTuple>; // string | number
//联合类型(Union Types)表示取值可以为多种类型中的一种
//交叉类型(Intersection Types)表示将多个类型合并为一个类型
//联合类型转交叉类型
//union 转 intersection
//union 转 intersection 的操作多用于 mixin 中
//https://github.com/Microsoft/TypeScript/issues/27907
type T1 = { name: string };
type T2 = { age: number };
type UnionToIntersection<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void } ? U : never;
type T3 = UnionToIntersection<{ a: (x: T1) => void; b: (x: T2) => void }>; // T1 & T2
readonly
或 ?
修饰符在一个映射类型里可以用前缀 +
或-
来表示这个修饰符应该被添加或移除符号 | 含义 |
---|---|
+? | 变为可选 |
-? | 变为必选 |
type Partial<T> = { [P in keyof T]?: T[P] };
interface A {
a1: string;
a2: number;
a3: boolean;
}
type aPartial = Partial<A>;
const a: aPartial = {}; // 不会报错
interface Company {
id: number
name: string
}
interface Person {
id: number
name: string
company: Company
}
type DeepPartial<T> = {
[U in keyof T]?: T[U] extends object
? DeepPartial<T[U]>
: T[U]
};
type R2 = DeepPartial<Person>
interface Person{
name:string;
age:number;
gender?:'male'|'female';
}
/**
* type Require<T> = { [P in keyof T]-?: T[P] };
*/
let p:Required<Person> = {
name:'zhufeng',
age:10,
//gender:'male'
}
interface Person{
name:string;
age:number;
gender?:'male'|'female';
}
//type Readonly<T> = { readonly [P in keyof T]: T[P] };
let p:Readonly<Person> = {
name:'zhufeng',
age:10,
gender:'male'
}
p.age = 11;
interface Animal {
name: string;
age: number;
gender:number
}
/**
* From T pick a set of properties K
* type Pick<T, K extends keyof T> = { [P in K]: T[P] };
*/
// 摘取 Animal 中的 name 属性
interface Person {
name: string;
age: number;
married: boolean
}
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
const result: any = {};
keys.map(key => {
result[key] = obj[key];
});
return result
}
let person: Person = { name: 'zhufeng', age: 10, married: true };
let result: Pick<Person, 'name' | 'age'> = pick<Person, 'name' | 'age'>(person, ['name', 'age']);
console.log(result);
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
function mapObject<K extends string | number, T, U>(obj: Record<K, T>, map: (x: T) => U): Record<K, U> {
let result: any = {};
for (const key in obj) {
result[key] = map(obj[key]);
}
return result;
}
let names = { 0: 'hello', 1: 'world' };
let lengths = mapObject<string | number, string, number>(names, (s: string) => s.length);
console.log(lengths);//{ '0': 5, '1': 5 }
type Point = 'x' | 'y';
type PointList = Record<Point, { value: number }>
const cars: PointList = {
x: { value: 10 },
y: { value: 20 },
}
type Proxy<T> = {
get(): T;
set(value: T): void;
}
type Proxify<T> = {
[P in keyof T]: Proxy<T[P]>
}
function proxify<T>(obj: T): Proxify<T> {
let result = {} as Proxify<T>;
for (const key in obj) {
result[key] = {
get: () => obj[key],
set: (value) => obj[key] = value
}
}
return result;
}
let props = {
name: 'zhufeng',
age: 10
}
let proxyProps = proxify(props);
console.log(proxyProps);
function unProxify<T>(t: Proxify<T>): T {
let result = {} as T;
for (const k in t) {
result[k] = t[k].get();
}
return result;
}
let originProps = unProxify(proxyProps);
console.log(originProps);
/**
* SetDifference (same as Exclude)
* @desc Set difference of given union types `A` and `B`
* @example
* // Expect: "1"
* SetDifference<'1' | '2' | '3', '2' | '3' | '4'>;
*
* // Expect: string | number
* SetDifference<string | number | (() => void), Function>;
*/
export type SetDifference<A, B> = A extends B ? never : A;
/**
* Omit (complements Pick)
* @desc From `T` remove a set of properties by key `K`
* @example
* type Props = { name: string; age: number; visible: boolean };
*
* // Expect: { name: string; visible: boolean; }
* type Props = Omit<Props, 'age'>;
*/
export type Omit<T, K extends keyof any> = Pick<T, SetDifference<keyof T, K>>;
/**
* Diff
* @desc From `T` remove properties that exist in `U`
* @example
* type Props = { name: string; age: number; visible: boolean };
* type DefaultProps = { age: number };
*
* // Expect: { name: string; visible: boolean; }
* type DiffProps = Diff<Props, DefaultProps>;
*/
export type Diff<T extends object, U extends object> = Pick<
T,
SetDifference<keyof T, keyof U>
>;
/**
* Intersection
* @desc From `T` pick properties that exist in `U`
* @example
* type Props = { name: string; age: number; visible: boolean };
* type DefaultProps = { age: number };
*
* // Expect: { age: number; }
* type DuplicateProps = Intersection<Props, DefaultProps>;
*/
export type Intersection<T extends object, U extends object> = Pick<
T,
Extract<keyof T, keyof U> & Extract<keyof U, keyof T>
>;
/**
* Overwrite
* @desc From `U` overwrite properties to `T`
* @example
* type Props = { name: string; age: number; visible: boolean };
* type NewProps = { age: string; other: string };
*
* // Expect: { name: string; age: string; visible: boolean; }
* type ReplacedProps = Overwrite<Props, NewProps>;
*/
export type Overwrite<
T extends object,
U extends object,
I = Diff<T, U> & Intersection<U, T>
> = Pick<I, keyof I>;
type Props = { name: string; age: number; visible: boolean };
type NewProps = { age: string; other: string };
// Expect: { name: string; age: string; visible: boolean; }
type ReplacedProps = Overwrite<Props, NewProps>;
type O1 = {
id: number;
name: string;
};
type O2 = {
id: number;
age: number;
};
//Compute的作用是将交叉类型合并
type Compute<A extends any> = A extends Function ? A : { [K in keyof A]: A[K] };
type R1 = Compute<{ x: "x" } & { y: "y" }>;
type Merge<O1 extends object, O2 extends object> = Compute<
O1 & Omit<O2, keyof O1>
>;
type R2 = Merge<O1, O2>;
readonly
移除type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
infer
关键字就是声明一个类型变量,当类型系统给足条件的时候类型就会被推断出来interface Action<T> {
payload?: T;
type: string;
}
class EffectModule {
count = 1;
message = "hello!";
delay(input: Promise<number>): Promise<Action<string>> {
let action: Promise<Action<string>> = input.then(i => ({
payload: `hello ${i}!`,
type: 'delay'
}));
return action;
}
setMessage(action: Action<Date>): Action<number> {
let action2: Action<number> = {
payload: action.payload!.getMilliseconds(),
type: "set-message"
};
return action2;
}
}
//把 EffectModule 中的方法名取出来
type methodsPick<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T];
//定义转换前后的方法
type asyncMethod<T, U> = (input: Promise<T>) => Promise<Action<U>> // 转换前
type asyncMethodConnect<T, U> = (input: T) => Action<U> // 转换后
type syncMethod<T, U> = (action: Action<T>) => Action<U> // 转换前
type syncMethodConnect<T, U> = (action: T) => Action<U> // 转换后
//条件类型+推断类型
type EffectModuleMethodsConnect<T> = T extends asyncMethod<infer U, infer V>
? asyncMethodConnect<U, V>
: T extends syncMethod<infer U, infer V>
? syncMethodConnect<U, V>
: never
type EffectModuleMethods = methodsPick<EffectModule>
//映射类型
type Connect = (module: EffectModule) => {
[M in EffectModuleMethods]: EffectModuleMethodsConnect<EffectModule[M]>
}
type Connected = {
delay(input: number): Action<string>;
setMessage(action: Date): Action<number>;
};
const connect: Connect = (m: EffectModule): Connected => ({
delay: (input: number) => ({
type: 'delay',
payload: `hello 2`
}),
setMessage: (input: Date) => ({
type: "set-message",
payload: input.getMilliseconds()
})
});
export const connected: Connected = connect(new EffectModule());
foo.ts
const foo = 123;
bar.ts
const bar = foo; // allowed
export const a = 1;
export const b = 2;
export default 'zhufeng';
import name, { a, b } from './1';
console.log(name, a, b);
export
向外导出export namespace zoo {
export class Dog { eat() { console.log('zoo dog'); } }
}
export namespace home {
export class Dog { eat() { console.log('home dog'); } }
}
let dog_of_zoo = new zoo.Dog();
dog_of_zoo.eat();
let dog_of_home = new home.Dog();
dog_of_home.eat();
import { zoo } from './3';
let dog_of_zoo = new zoo.Dog();
dog_of_zoo.eat();
namespace Numbers {
export let a = 1;
export let b = 2;
export let c = 3;
}
var Numbers;
(function (Numbers) {
Numbers.a = 1;
Numbers.b = 2;
Numbers.c = 3;
})(Numbers || (Numbers = {}));
export module Box{
export class Book1{}
}
src\table2.ts
export module Box{
export class Book1{}
}
src\table3.ts
export module Box{
export class Book1{}
}
src\table1.ts
namespace Box{
export class Book1{}
}
src\table2.ts
namespace Box{
export class Book1{}
}
src\table3.ts
namespace Box{
export class Book1{}
}
src\table1.ts
export class Book1 { }
src\table2.ts
export class Book1 { }
src\table3.ts
export class Book1 { }
declare var 声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare namespace 声明(含有子属性的)全局对象
interface 和 type 声明全局类型
declare let name: string; //变量
declare let age: number; //变量
declare function getName(): string; //方法
declare class Animal { name: string } //类
console.log(name, age);
getName();
new Animal();
export default {};
声明jQuery对象
declare const $: (selector: string) => { //变量
click(): void;
width(length: number): void;
};
$('#root').click();
console.log($('#root').width);
declare enum
定义的枚举类型declare enum Seasons {
Spring,
Summer,
Autumn,
Winter
}
let seasons = [
Seasons.Spring,
Seasons.Summer,
Seasons.Autumn,
Seasons.Winter
];
declare
定义的类型只会用于编译时的检查,编译结果中会被删除。上例的编译结果如下
var seasons = [
Seasons.Spring,
Seasons.Summer,
Seasons.Autumn,
Seasons.Winter
];
也可以同时使用declare
和 const
declare const enum Seasons {
Spring,
Summer,
Autumn,
Winter
}
let seasons = [
Seasons.Spring,
Seasons.Summer,
Seasons.Autumn,
Seasons.Winter
];
编译结果
var seasons = [
0 /* Spring */,
1 /* Summer */,
2 /* Autumn */,
3 /* Winter */
];
namespace
表示一个全局变量包含很多子属性declare namespace ${
function ajax(url:string,settings:any):void;
let name:string;
namespace fn {
function extend(object:any):void;
}
}
$.ajax('/api/users',{});
$.fn.extend({
log:function(message:any){
console.log(message);
}
});
export {};
*.d.ts
typings\jquery.d.ts
declare const $:(selector:string)=>{
click():void;
width(length:number):void;
}
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2015",
"outDir":"lib"
},
"include": [
"src/**/*",
"typings/**/*"
]
}
src\test.ts
$('#button').click();
$('#button').width(100);
export {};
cnpm i jquery -S
//对于common.js风格的模块必须使用 import * as
import * as jQuery from 'jquery';
jQuery.ajax('/user/1');
cnpm i @types/jquery -S
tsconfig.json
types\jquery\index.d.ts
declare function jQuery(selector:string):HTMLElement;
declare namespace jQuery{
function ajax(url:string):void
}
export default jQuery;
paths
,那么在引入包的的时候会自动去paths
目录里找类型声明文件compilerOptions
里的 paths
属性来配置路径映射paths
是模块名到基于baseUrl
的路径映射的列表{
"compilerOptions": {
"baseUrl": "./",// 使用 paths 属性的话必须要指定 baseUrl 的值
"paths": {
"*":["types/*"]
}
}
import $ from "jquery";
$.ajax('get');
package.json
中的 types
或 typings
字段指定一个类型声明文件地址index.d.ts
文件.d.ts
文件{
"name": "myLib",
"version": "1.0.0",
"main": "lib/index.js",
"types": "myLib.d.ts",
}
`
declare var String: StringConstructor;
interface StringConstructor {
new(value?: any): String;
(value?: any): string;
readonly prototype: String;
}
interface String {
toString(): string;
}
//扩展类的原型
interface String {
double():string;
}
String.prototype.double = function(){
return this+'+'+this;
}
console.log('hello'.double());
//扩展类的实例
interface Window{
myname:string
}
console.log(window.myname);
//export {} 没有导出就是全局扩展
types\global\index.d.ts
declare global{
interface String {
double():string;
}
interface Window{
myname:string
}
}
export {}
关键字 | 作为类型使用 | 作为值使用 |
---|---|---|
class | yes | yes |
enum | yes | yes |
interface | yes | no |
type | yes | no |
function | no | yes |
var,let,const | no | yes |
class Person{
name:string=''
}
let p1:Person;//作为类型使用
let p2 = new Person();//作为值使用
interface Animal{
name:string
}
let a1:Animal;
let a2 = Animal;//接口类型不能用作值
use.js
interface Animal{
name:string
}
let a1:Animal={name:'zhufeng',age:10};
console.log(a1.name);
console.log(a1.age);
//注意不要加export {} ,这是全局的
types\animal\index.d.ts
interface Animal{
age:number
}
class Form {
username: Form.Item='';
password: Form.Item='';
}
//Item为Form的内部类
namespace Form {
export class Item {}
}
let item:Form.Item = new Form.Item();
console.log(item);
namespace
来扩展函数function greeting(name: string): string {
return greeting.words+name;
}
namespace greeting {
export let words = "Hello,";
}
console.log(greeting('zhufeng'))
enum Color {
red = 1,
yellow = 2,
blue = 3
}
namespace Color {
export const green=4;
export const purple=5;
}
console.log(Color.green)
import { createStore, Store } from 'redux';
type StoreExt = Store & {
ext: string
}
let store: StoreExt = createStore(state => state);
store.ext = 'hello';
{
"compilerOptions": {
"declaration": true, /* Generates corresponding '.d.ts' file.*/
}
}
npm link
npm link zf-events
import { EventEmitter } from "zf-events";
console.log(EventEmitter.defaultMaxListeners);
var e = new EventEmitter();
e.on('message', function (text:string) {
console.log(text)
})
e.emit('message', 'hello');
export type Listener = (...args: any[]) => void;
export type Type = string | symbol
export class EventEmitter {
static defaultMaxListeners: number;
emit(type: Type, ...args: any[]): boolean;
addListener(type: Type, listener: Listener): this;
on(type: Type, listener: Listener): this;
once(type: Type, listener: Listener): this;
}