TypeScript的介绍
1.ts是由微软开发的开源变成语言(vscode和ts都是微软提供的,vs里面很多ts的适配,里面有很多ts的插件,让写法更佳舒适)
2.ts是js的超集(超集的理解:ts在js之上,包含js所有最新的语法特性,包含es6、es7所对应的写法)
【 es 3一个版本,es5一个版本 ,es 6一个版本,es2017,2018,2019都是es7版本】
3.ts是开发大型应用的基石(为什么要学ts?很多大型项目都是基于ts来开发的,比如angular,vscode,vue 3.0,react;越来越多的特性都偏向ts,大型应用基本都用ts语法做支持)
4.ts提供了更丰富的语法提示
5.ts在编译阶段能检查语法错误
1.先去官网安装node
2.npm i typescript
错误检查&ts的编译
(为什么需要编译?因为浏览器无法识别ts,所以需要将ts编译成js)
var a:string='123';
console.log(a);
执行tsc index.ts,将index.ts文件编译为index.js文件。
创建配置文件:tsc --init , 配置完rootDir和outDir后,直接输入tsc编译
错误检查:
但是这段代码在js中却可以正确运行
js是动态类型,可以动态更改变量的类型
var a = '123';
a=123;
console.log(a);
ts是静态类型的(一旦定义完类型后就无法更改它的类型):
ts中的数据类型&&ts新增的语法特性
js:基本类型:boolean 、string、number、null、undefined、symbol
引用类型:object
ts:数据类型:
-
number
let num: number = 6;
-
string
let str: string = '123';
-
boolean
let flag: boolean = false;
-
any
let obj:{ // 对象类型的注解
str: string,
toString: () => void
} = {
str: '124',
toString: function () {
console.log(obj);
// 或这样写1
// interface Obj {
// str: string;
// toString: () => void
// let obj: Obj = {
// str: '123',
// toString:function () {
// }
// 或这样写2
// type Obj = {
// str: string;
// toString: () => void
// let obj: Obj = {
// str: '123',
// toString:function () {
// }
// }
let obj:any = {
str: '124',
toString: function () {
console.log(obj);
表示任意数据类型。
1)如果是对象的话,any不能提示原有的属性和方法
2)如果是不同变量的话,可以是任意的数据类型
3)未给初始值的变量类型为any (比如let a; 这里的a就是any类型,所以可以a='123'; a=123;不会报错)
-
undefined ,
let num: number = undefined;
配置项中--strictNullChecks会严格检查null和undefined类型,赋值会赋不成功 (
想赋的话把此参数改成true,但是官网不建议这么赋值,想这样赋的话就用联合项
)
推荐写法:
let num: number | undefined = undefined;
-
null ,null和undefined是所有类型的子类型。
-
never,表示永不存在值的类型。当报错或死循环的时候用它。
function error(message) {
throw new Error(message);
function fail() {
return error('something failed');
function infiniteLoop() {
while (true) {
}
-
void :表示没有类型,用在函数没有返回值的时候。
function test(): void {
console.log(1111);
}
-
枚举
-
数组 :
// 数组的注解;有3种表示方法
// 1.类型[]
let arr1: number[] = [1, 2, 3];
// 2.Array<类型> Array<number>
let arr2: Array<number> = [1, 2, 3];
// 3.interface
interface NumberArray {
[index: number]: number;
let list: NumberArray = [1, 2, 3, 4];
// 类数组
function test() {
let args: IArguments = arguments;
}
-
元祖
Object:非原始类型。
// 全局声明一个函数,规定这个函数的参数是对象或null,没有返回值
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create([]); // OK
create(function(){}); // OK
create({}); // OK
// 由此看出,这里的object就是非原始类型
进一步的区分:interface、
number[]、string[]、boolean[]
数组中泛型的写法:
Array<number>、Array<string>、Array<boolean>
函数注解:
let test=function(a:number,b:number):number{
return a+b;
开发者自己定义的ts变量类型就是类型注解
当我们没有指定类型的时候,ts会自动帮我们分析当前的变量类型。
(当类型推断能推断出正确的类型时,就不用类型注解,比如函数这种情况下
function add(a, b) {
return a + b;
add(1, 2);
1.联合类型的公有属性是不会报错的;比如toString(),number和string类型都有这个方法就不会报错。
2.在赋值的时候就已经确定了数据的类型。不能更改类型了。
对对象的形状进行描述;
对类的一部分的行为的抽象;
interface Person {
name: string;
age: number;
let person: Person = {
name: "lily",
age: 18,
【interface定死了以后,它的属性不可多,也不可少
如果想要多或少属性怎么办呢?
可少;可以用可选属性?:
可多;用任意属性[propName:string]:any
如果遇到id这种唯一不可变的属性,可以用readonly属性
ReadonlyArray<T>
类型
let ro: ReadonlyArray<number> = [1,2,3,4];
readonly
还是 const?
当做变量用const,当做属性用readonly(主要判断属性是否可写)
函数类型接口
(之前是按这样的方式来注解函数,有1个问题:在注解函数的同时实现了这个函数,如果我只想要定义这个函数类型,没办法定义)
function mySearch1(source: string, subString: string): boolean {
let result = source.search(subString);
return result > -1;
函数表达式的方式太冗长
let mySearch: (source: string, subString: string) => boolean = function (
source: string,
subString: string
): boolean {
let result = source.search(subString);
return result > -1;
我们希望抽象出来一个参数是source和subString,返回值是boolean的函数类型
第一种(不常见):
type SearchFunc = (source: string, subString: string) => boolean;
let mySearch: SearchFunc = (source: string, subString: string): boolean => {
let result = source.search(subString);
return result > -1;
第二种(常见):
interface SearchFunc {
(source: string, subString: string): boolean;
let mySearch: SearchFunc = (source: string, subString: string): boolean => {
let result = source.search(subString);
return result > -1;
可索引类型接口(就是数组类型接口)
当索引是number时候,就可以描述一个数组:
interface numberArr {
[index: number]: number;
let test: numberArr = {
0: 1,
1: 2,
let arr: numberArr = [1, 2, 3];
注意:索引签名支持2种形式:字符串和数字。因为所有的number最终会转为字符串,当使用 number
来索引时,JavaScript会将它转换成string
然后再去索引对象。
官网例子:
(1)为什么第一个索引签名是number会报错? 因为Animal父类的name是string类型
(2)那如果把第一个改成string又为什么会报错?因为两者重复。
(3)如果把第二个索引签名改成number类型为什么不报错?因为所有number最后都被会js转成string类型。
(4)如果number都会被转为string,那么回到第一个问题,为什么不能给第一个索引签名设置为number?因为string类型范围比number范围大,Animal是父类, 父类必须比子类范围要大,所以第一个必须是string,第二个必须是number
索引签名有点类似老大的意思,索引签名是个大范围,接口里面的属性必须得在这个范围内。
interface NumberDictionary {
[index: string]: number | string;
length: number;
name: string;
索引签名也可以设置为只读:
类 类型接口
可以用接口来描述类吗?不完全可以,因为类有构造器。
“对类的一部分的行为的抽象”的理解:
把类上 抽象的公共属性和方法,抽成一个接口。
想要解决这个报错问题,可以改配置项"noImplicitAny": false
interface Alarm {
alert(): void;
interface Light {
color: string;
lightOn(): void;
lightOff(): void;
class Door {}
class SecurityDoor extends Door implements Alarm {
alert() {
console.log("hi");
class Car implements Alarm, Light {
color = "red";
lightOn() {}
lightOff() {}
alert() {}
类和接口对比:
(1)抽象类中定义抽象方法要实现;
接口中定义的属性方法都要实现;
(2)抽象类中的方法属性可以通过继承方式来拿到;
接口的抽象方法需要实现;实现接口的话,接口所有方法都要实现;
(3)1个类可以实现多个接口;多个子类可以继承1个抽象的类
用类 分别实现类的静态部分与实例部分
(类的静态部分和实例部分需要单独写)
想通过接口直接实现类的构造函数是会报错的,因为constructor存在于类的静态部分,所以不在检查的范围内。
但是也有办法:
单独抽离1个构造函数的interface,用函数检查的方式单独检查函数的interface,然后返回一个new的实例
interface ClockInterface {
currentTime: Date;
getTime(h: number, m: number): void;
interface ClockConstructor {
new (h: number, m: number): any;
getTime1():void; // 相当于一个静态方法
class Clock implements ClockInterface {
currentTime = new Date();
getTime() {}
constructor(h: number, m: number) {}
static getTime1() { }
function createClock(Clock: ClockConstructor, h: number, m: number) {
return new Clock(h, m);
let clock = createClock(Clock, 12, 12);
就是接口可以继承接口 或 类可以实现接口。
“接口可以继承接口”的理解:
接口是对象形状的描述,接口继承接口就相当于在原本基础上进行进一步的约束。
interface Shape {
color: string;
interface Square extends Shape {
sideLength: number;
let square = <Square>{}; // 这里接口继承接口,然后用断言的方式赋初始值
square.color = "blue";
square.sideLength = 10;
官方这里没有解释为什么这里要用类型断言:
如果let square:Square;这样写,报错提示:“在赋值前就使用了变量”;定义了square,但是没有初始值,但是一旦给初始值,就回去检查它类型,就会类型不符,所以用类型推断方式。
接口的混合类型
函数类型的interface,可以通过添加属性的方式来实现对象的interface
相当于函数类型interface+对象类型interface
interface Counter {
(start: number): string;
interval: number;
reset(): void;
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
接口继承类
1.类可以实现接口:类可以抽象一部分功能,让接口实现
2.接口可以继承接口:接口相当于一个对象,继承一个对象,就是能在这个对象上面添加更对属性
3.接口可以继承类:类也是接口,接口可以继承接口,所以接口能继承类。
1.image重复,改成image1。
2.提示错误实现接口SelectableControl,因为接口继承Control接口:在Image里定义state,但是因为是私有成员,所以没法直接实现state。
接口和类的关系:
// 2种写法效果是一样的
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
interface PointerInterface {
x: number;
y: number;
interface Point3D extends Point {
z: number;
interface Point3D extends PointerInterface {
z: number;
虽然这种写法方式没有问题,但容易引起大家歧义,不建议大家用接口继承类。
函数有2种写法:函数声明和函数表达式。
函数声明的注解方式:
function test(a: number, b: number): number {
return a + b;
函数表达式的注解方式:
let test1: (a: number, b: number) => number = (a, b) => {
return a + b;
let test2: (a: number, b: number) => {} = (a, b) => {
return { a, b };
console.log(test2(1, 2));
当参数少了的时候同interface可以设置可选参数
【可选参数注意事项】
(1)默认把可选参数放在后面,必选参数不能位于可选参数后。
function test(a: string, b?: string): string {
return "" + a + b;
console.log(test("1", "2"));
(2)默认值和可选参数不能放一起。
当参数多了可以用剩余参数 ,...args,...args是个数组,必须放到最后面
// 语法
function test1(
{ first, second }: { first: number; second: number } = { first: 1, second: 2 }
return first + second;
function test2({ first = 2 }: { first: number }) {
return first;
// 解构赋值
// 变量和属性名一致时,对象可简写
// let {a:a,b:b,c:c}={a:1,b:2,c:3};
// 等价于
// let {a,b,c}={a:1,b:2,c:3};
// 不完全结构是值(右边)多了;结构失败是变量(左边)多了
关于this
this有4个规则:
(1)默认情况下this指向window。(函数的独立调用、立即执行函数、闭包中的this都指向window)
(2)隐式绑定,谁调用就指向谁。
(3)显示绑定,call、apply、bind绑定this指向
(4)new的this指向实例化后的对象
报错的this指向window,我们希望这里的this指向deck。
就可以这么写
noImplicitThis配置项
控制当源文件中存在this的值是any的时候是否报错,noImplicitThis默认为false,即当源文件中存在this为any的情况也不报错,如果设置为true则会报错
函数的重载
ts的重载解决的只是表意问题,能够表意更清楚
function reverse(x: string): string;
function reverse(x: number): number;
function reverse(x: number | string) {
if (typeof x === "string") {
return x.split("").reverse().join("");
} else {
return Number(x.toString().split("").reverse().join(""));
console.log(reverse(123));
类的注解方式
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
greet() {
return "Hello, " + this.greeting;
let greeter = new Greeter("world");
继承中的super在constructor内部默认是构造函数;在这以外super指的是父类。
class Animal {
name: string;
constructor(theName: string) {
this.name = theName;
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
class Snake extends Animal {
constructor(name: string) {
super(name);
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
let sam = new Snake("Sammy the Python");
sam.move();
类成员的修饰符
public:
(1)自身调用:
(2)子类调用:
(3)实例调用:
private:
(1)只能自身调用
protected:(控制可访问否,上面都是)
(1)自身可以调用(2)子类可以调用
readonly:(控制可写否)
顺序:public readonly
不能修饰成员方法
参数属性可以方便地让我们在一个地方定义并初始化一个成员。
class Octopus1 { // 简写
constructor(private theName: string) {}
class Octopus2 {
private theName: string;
constructor(theName: string) {
this.theName = theName;
存取器(改变赋值和读取的行为)
1.成对出现,定义了getter一定也有setter,并且修饰同一属性
2.这里的赋值操作相当于调用了set方法,判断里用到了fullName属性,相当于调用了get方法。
静态属性用static来定义,通过类/构造函数来访问。如果是实例属性用this.来访问的。
abstract关键字来定义抽象类,抽象类能够作为其它派生类的基类使用。
特点:(1)无法创建实例
(2)抽象类中的抽象方法一定要实现
abstract class Animal {
abstract makeSound(): void; // 发声方式
move(): void {
console.log("roaming the earch...");
class Snack extends Animal {
makeSound() {
console.log("zzzzzzzz");
move(): void {
console.log("roaming the earch...");
class Cow extends Animal {
makeSound() {
console.log("mmmmmmmmmm");
move(): void {
console.log("roaming the earch...");
1.定义了一个类的时候,相当于定义了一个类型/构造函数
2.接口可以继承
TypeScript的介绍1.ts是由微软开发的开源变成语言(vscode和ts都是微软提供的,vs里面很多ts的适配,里面有很多ts的插件,让写法更佳舒适)2.ts是js的超集(超集的理解:ts在js之上,包含js所有最新的语法特性,包含es6、es7所对应的写法)3.ts是开发大型应用的基石(为什么要学ts?很多大型项目都是基于ts来开发的,比如vscode,vue 3.0,react;越来越多的特性都偏向ts,大型应用基本都用ts语法做支持)4.ts提供了更丰富的语法提示5.ts在
1、函数内部的变量名如果第一次出现,且出现在=前面,即被视为定义一个局部变量,不管全局域中有没有用到该变量名,函数中使用的将是局部变量,例如:
num = 100
def func():
num = 123
print(num)
func()输出:
说明函数中定义的num是一个局部变量,会将全局变量覆盖。再例如:
num = 100
def func(
func()
会出现local variable ‘x’ referenced before assignment的错误是因为全局变量与局部变量同名时,当你想在函数内部中修改外部变量的值,python首先会认为该变量是局部变量,函数内部没有定义局部变量a=value,而内部作用域想要改变外部作用域的值,就要用到global关键词。
a = 13
def func():
最近在练手
typescript的过程中,遇到了两个小问题,虽然当时很不习惯,但解决问题后,也算是熟悉和加深了对
typescript的理解。
一、显式
赋值断言
let a: string;
if (!a)
a = 'aa';
console.log(a)
会出现错误提示:Variable ‘a’ is used before being assigned.
在
赋值前使用了
变量a。
let a!: string; //
变量后加!
if (!a)
a = 'aa';
编译一个ts文件,开发react后缀 .tsx
命令:tsc hello.ts
含义:将ts文件转成js文件,如果有ts语法错误,会报错,但是仍然会生成js文件,我们仍然可以
使用这个js文件;
如果想要在报错的时候终止js的生成,可以在tsconfig.json中配置onEmiOnError即可
ts只会在编译时对类型进行检查,如果发现错误,编译时就会报错;(静态检查)
而js是再运行时,发现错误,会报错;(动态检查)
3. 数据类型
在前一篇文章,我们了解了TS的安装使用以及基础类型,本文接着学习类型推断以及变量声明的内容。TS的核心功能就是,我们需要给变量或方法添加类型注解来表明数据类型。当没有提供类型注解时,TS编译器会利用来推断类型。
如果由于缺乏声明而不能推断出类型,那么它的类型被视作默认的动态 类型。有些情况下,我们会比TS清楚更确切的类型,可以使用手动指定一个值的类型,即允许变量从一种类型更改为另一种类型。它没有运行时的影响,只是在起作用。类型断言有两种形式,第一种是语法:第二种是 语法:举个例子:
通过上面的例子可以知