安装
npm i typescript -g
转换成js
tsc 文件名.ts
- 方法二
- vscode > terminal > run task > tsc:watch -tsconfig.json
- vscode > terminal > run task > tsc:build -tsconfig.json
- 方法三
- package.json中写脚本: "build": "tsc",npm run build
生成配置文件tsconfig.json
tsc --init
数据类型
- 如果文件里出现了export或import,ts会把这个文件当成一个模块,文件中的变量就会变成私有变量,不会和全局变量冲突
let married: boolean = false;
let age: number = 0;
let name: string = 'zhangsan'
let arr1:number[] = [1,2,3]
let arr2: Array<number> = [7,8,9]
let school: [string,number] = ['zhangsan',5]
enum Gender {
MALE,
FEMAL
}
const enum Colors {
Red,
Yellow,
Blue
}
let root: HTMLElement | null = document.getElementById('root')
root!.style.color = 'red';
let root: any = document.getElementById('root')
root.style.color = 'red'
let x:number;
x = 1;
x = undefined;
x = null;
function greeting(name: string): void {
console.log(name);
}
function error(msg: string): never {
console.log(msg);
throw new Error(msg);
console.log('over message')
}
let ret: never = error('hello')
functiion loop(): never {
while(true) {}
}
function sum(x:number|string){
if (typeof x === 'number') {
console.log(x)
} else if(typeof x === 'string') {
console.log(x)
} else {
console.log(x)
}
}
export {}
枚举类型
普通枚举编译成es5
enum Gender {
MALE,
FEMAL
}
console.log(Gender)
var Gender;
(function(Gender) {
Gender[Gender['MALE'] = 0] = 'MALE';
Gender[Gender['FEMALE'] = 1] = 'FEMALE';
})(Gender || (Gender = {}))
console.log(Gender)
常量枚举编译成es5
const enum Colors {
Red,
Yellow,
Blue
}
let myColors = [Colors.Red, Colors.Yellow, Colors.Blue]
var myColors = [0,1,2]
枚举类型与数字类型兼容
enum Colors {
Red,
Yellow
}
let c: Colors
c = Colors.Red
c = 0
let n: number
n = Colors.Yellow
类型断言
let name: string|number;
(name as string).length;
(name as number).toFixed(2);
(<number>name).toFixed(2)
字面量类型
- 字面量是值的联合,联合是类型的联合
- type是TS的关键字,用来声明一个新的类型
- 可以把字符串/数字/布尔值字面量组成一个联合类型
type myType = 1|'one'|true;
let t1: myType = 1
let t2: myType = 'one'
let t3: myType = true
函数
type UserFunction = (a: string, b: string) => string
let getUserName: UserFunction = function(firstName: string, lastName: string) {
return firstName + lastName;
}
function print(name: string, age?:number): void {
console.log(name,age)
}
function ajax(url: string, method: string = 'GET') {
console.log(url,method)
}
function sum(prefix: string, ...numbers: number[]) {
return prefix + numbers.reduce((a,b) => a+b)
}
let obj: any = {};
function attr(a:string,b:string);
function attr(a:number,b:number);
function attr(a:string|number,b:string|number){
if (typeof val === 'string') {
obj.name = val;
} else if(typeof val === 'number') {
obj.age = val;
}
}
attr(1,1);
attr('a','b');
attr(1,'b');
type functionType = (a: number, b: number) => number
let sum: functionType;
function f1(a:number):number {
return a
}
sum = f1
type GetPerson = () => {name: string,age:number}
let getPerson: GetPerson;
function g1() {
return {name:'zz',age:10,home:'beijing'}
}
getPerson = g1
let sourceFunc = (a: number | string) => {}
let targetFunc = (a: number | string | boolean) => {}
基本类型的兼容性
let num: string | number;
let str: string = 'zll';
num = str
let num2:{
toString(): string
}
let str2: string = 'jiagou'
num2 = str2
类
class Person {
name: string;
getName():void {
console.log(this.name)
}
}
let p1: Person = new Person;
p1.name = 'zll';
pi.getName()
存取器
class User {
myName: string = '';
constructor(myName: string) {
this.myName = myName;
}
get name(){
return this.myName;
}
set name(value) {
this.myName = value.toUpperCase();
}
}
let user = new User('');
user.name = 'zll'
class User {
constructor(public myName: string) {
}
get name(){
return this.myName;
}
set name(value) {
this.myName = value.toUpperCase();
}
}
class User {
public readonly PI = 3.14;
constructor(public myName: string) {
}
get name(){
return this.myName;
}
set name(value) {
this.myName = value.toUpperCase();
}
}
public private protected
- public 属性意味着这个属性可以被自己类本身.子类和其他类访问
- protected属性表示这个属性只有自己类本身和子类能访问,其他类不能访问
- private属性表示这个属性只能被本身访问,子类和其他类都不能访问
class Father {
constructor(public name: string, protected age:number, private money:number) {
}
getMoney(){
console.log(this.money)
}
}
class Child extends Father {
constructor(name: string,age:number,money:number) {
super(name,age,money)
}
getName(){
console.log(this.name)
}
getAge(){
console.log(this.age)
}
}
let child = new Child('zll',10,100);
child.getName();
child.getAge();
child.getMoney();
child.name;
child.age;
child.money;
装饰器
类装饰器
function enchancer(target:new () => Person) {
target.prototype.name = 'zll';
target.prototype.eat = function() {
console.log(this.name)
}
}
@enchancer
claass Person {
}
let p: any = new Person();
p.name;
p.eat()
装饰器工厂1
function enhancer(name: string) {
return function(target:new () => Person) {
target.prototype.name = name;
target.prototype.eat = function() {
console.log(this.name)
}
}
}
@enhancer('zll')
class Person {
}
let p: any = new Person();
p.name;
p.eat()
装饰器工厂2
function enchancer(target:new () => Person) {
return class {
constructor(public age:number) {
}
name: string = 'zll';
eat(){
console.log(this.name)
}
}
}
@enchancer
claass Person {
constructor(public age: number){
}
}
let p = new Person(10);
p.name;
p.eat()
属性装饰器
function upperCase(target: any, property: string) {
let value = target[property];
const getter = () => value;
const setter = (newValue: string) => {
value = newValue.toUpperCase();
}
if(delete target[property]) {
Object.defineProperty(target,property,{
get:getter,
set: setter,
enumerable: true,
configurable:true
})
}
}
class Person {
@upperCase
name: string = 'zll';
}
let p = new Person
p.name = 'wang'
方法装饰器
function noEnumerable(target: any, property: string, descriptor: propertyDescriptor){
descriptor.enumerable = false;
}
class Person {
name: string = 'zll'
@noEnumerable
getName() {
console.log(this.name)
}
}
参数装饰器
interface Person {
age: number
}
function addAge(target: any, methodName: string, paramsIndex:number) {
target.age = 10
}
class Person {
login(username: string, @addAge password: string) {
console.log(username, password)
}
}
抽象类
- 抽象描述一种抽象的状态,无法被实例化,只能被继承
- 抽象方法不能在抽象类中实现,只能在具体子类中实现
- 重写和重载
- 重载指的是为一个函数提供多个类型 定义,或者说函数声明
- 重写指的是不同的子类以不同的方式实现父类的方法
abstract class Animal {
name: string;
abstract speak(): void
}
class Cat extends Animal {
speak():void {
console.log('喵喵喵')
}
}
let cat = new Cat();
cat.speak()
class Dog extends Animal {
speak():void {
console.log('汪汪汪')
}
}
let dog = new Dog();
dog.speak()
兼容性
class Animal {
name: striing
}
class Bird extends Animal {
swing: number
}
let a: Animal;
a = new Bird();
接口
对象的形状
interface Speakable {
name: string;
speak(): void;
}
let person: Speakable = {
name: 'zll',
speak() {}
}
行为的抽象
interface Speakable {
speak(): void;
}
interface Eatable {
eat(): void;
}
class Person implements Speakable,Eatable {
speak() {
console.log('speak')
}
eat(): void {
console.log('eat')
}
}
任意属性
interface Person extends Record<string, any>{
name: string,
age: number
}
let p:Person={
name: 'zll',
age: 10,
home: 'beijing',
today: 1
}
函数接口类型
interface Cost {
(price: number): number
}
let cost: Cost = function(price: number): number {
return price * 8
}
可索引接口
interface UserInterface {
[index: number] : string
}
let arr: UserInterface = ['1','2']
let obj:UserInterface = {
0: 'a',
1: 'b'
}
类implements接口
interface Speakable {
name: string,
speak(words): void
}
class Dog implements Speakable {
name: string;
speak(words): void {
console.log(words)
}
}
let dog = new Dog
dog.speak('汪汪汪')
接口约束类
class Animal {
constructor(public name: string) {
}
}
interface WithNameClazz {
new(name: string): Animal
}
function create(clazz: WithNameClazz,name: string) {
return new clazz(name);
}
let a = create(Animal,'zll')
console.log(a)
兼容性1
- 如果传入的变量和声明的类型不匹配 ts会进行兼容性检查
- 目标类型声明的变量在源类型中都存在,那么就是兼容的
interface Animal {
name: string,
age: number
}
interface Person {
name: string,
age: number,
gender: number
}
function getName(animal: Animal): string {
return animal.name
}
let p: Person = {name:'zll', age:10, gender:0}
getName(p)
兼容性2
interface Event {
timeStamp: number
}
interface MouseEvent extends Event {
eventX: number,
eventY: number
}
interface KeyEvent extends Event {
keyCode: number
}
function addEventListener (eventType: string, handler:(event: MouseEvent) => void) {}
addEventListener('cliick', (event: Event) => {})
问题
- interface对比type?
- 相同点
都能描述对象类型
都能实现继承,interface用extends,type配合交叉类型
- 不同点
type除了能描述对象还可以用来自定义其他类型
同名的interface会合并,同名type会报错
- 类和interface的区别?
- 接口只是一个类型,用来修饰对象,或者被类去实现,经过ts编译之后就消失
- 类既是类型(类的实例的类型),也是值(构造函数)
- 类的接口和抽象类的区别?
泛型(难点)
- 在定义函数/接口/类的时候,不预先指定具体的类型,而是使用的时候指定
function createArray<T>(length: number, value: T):T[] {
let result: T[] = [];
for(let i = 0;i<length;i++) {
result[i] = value;
}
return result;
}
let result = createArray<string>(3,'x');
console.log(result)
类数组
function sum(...args: number[]) {
for(let i = 0;i<args.length;i++) {
console.log(args[i])
}
}
sum(1,2,3)
泛型类
class MyArray<t> {
private list: T[] = [];
add(value:T) {
this.list.push(value)
}
}
let arr = new MyArray<number>()
arr.add(1)
泛型接口
interface Calculate {
<T>(a:T,b:T):T
}
let add: Calculate = function<T>(a:T,b:T) {
return a;
}
interface Calculate<A> {
<B>(a:A,b:B):A
}
let add: Calculate<number> = function<B>(a:number,b:B) {
return a;
}
add<string>(1,'b')
默认泛型
interface Calculate<A = number> {
<B>(a:A,b:B):A
}
let add: Calculate = function<B>(a:number,b:B) {
return a;
}
add<string>(1,'b')
接口泛型约束
- 默认情况下,不能调用泛型上的任何属性和方法,因为在定义的时候根本不知道将会传入什么值
interface LengthWise {
length: number
}
function logger<T extends LengthWise>(val:T) {
console.log(val.length)
}
logger<string>('d')
泛型类型别名
type Cart<T> = {list:T[]} | T[]
let c1: Cart<string> = {list:['1']}
let c2: Cart<number> = [1,2,3]
泛型兼容性
interface Empty<T> {}
let x!: Empty<string>;
let y!: Empty<number>;
x = y
interface Empty1<T> {
data: T
}
let x1!: Empty1<string>;
let y1!: Empty1<number>;
x1 = y1;