前言:TypeScript是Js的一个超集,而且支持ES6,是一种面向对象的编程方法,经常使用的用法主要包括如下几个部分:基础类型,类型批注,类型推断,接口,枚举,修饰符,泛型,命名空间,类,元组等。node
使用npm安装面试
npm config set registry https://registry.npm.taobao.org
复制代码
安装TypeScripttypescript
npm install -g typescript
复制代码
而后就能够用tsc
命令来编译ts文件npm
tsc -v #查看ts版本号
tsc app.ts #编译指定ts文件
复制代码
编译完成后会在该文件的相同目录下生成app.js
文件,而后使用node app.js
便可运行该文件编程
或者安装ts-node插件,而后能够直接使用命令ts-node
运行ts文件json
ts-node app.ts
复制代码
在ts中,变量声明的时候同时须要声明变量的类型数组
const count :number=111
const myName:String="aaa"
复制代码
const myObj:{
name:string,
age:number
}={
name:"张三",
age:18
}
复制代码
const names:string[]=["aaa","bbb","ccc"]
复制代码
class Person{}
const zhangsan:Person=new Person()
复制代码
const seeZhangSan:()=>string=()=>{return "lisi"}
复制代码
var val:string|number
val = 12
console.log("数字为 "+ val) //数字为 12
val = "Hello"
console.log("字符串为 " + val) //字符串为 Hello
//若是赋值其余类型就会报错
var val:string|number
val = true //报错
复制代码
也能够将联合类型做为函数参数使用安全
function disp(name:string|string[]) {
if(typeof name == "string") {
console.log(name)
} else {
var i;
for(i = 0;i<name.length;i++) {
console.log(name[i])
}
}
}
disp("Runoob")
console.log("输出数组....")
disp(["Runoob","Google","Taobao","Facebook"])
复制代码
联合类型数组markdown
var arr:number[]|string[];
var i:number;
arr = [1,2,4]
console.log("**数字数组**")
for(i = 0;i<arr.length;i++) {
console.log(arr[i])
}
arr = ["Runoob","Google","Taobao"]
console.log("**字符串数组**")
for(i = 0;i<arr.length;i++) {
console.log(arr[i])
}
复制代码
在ts中,函数能够指定参数类型与返回值类型app
//函数参数类型注解
function getTotal1(one:number,two:number){
return one+two
}
let total1=getTotal1(1,2)
//函数返回值类型注解
function getTotal2(one:number,two:number):number{
return one+two
}
let total2=getTotal2(1,2)
//函数参数是对象时的注解方式
function add({one,two}:{one:number,two:number}){
return one+two
}
let total3=add({one:1,two:2})
function getNumber({one}:{one:number}){
return one
}
let one=getNumber({one:1})
复制代码
在ts函数中,可使用?
定义可选参数
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // 正确
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
复制代码
能够指定参数的默认传入值,若是调用该函数时未传入参数则使用该默认值
function calculate_discount(price:number,rate:number = 0.50) {
var discount = price * rate;
console.log("计算结果: ",discount);
}
calculate_discount(1000)
calculate_discount(1000,0.30)
复制代码
当咱们不知道要向函数传入多少个参数,这个时候咱们就可使用剩余参数来定义,剩余参数容许咱们将一个不缺性数量的参数做为数组传入
function addNumbers(...nums:number[]) {
var i;
var sum:number = 0;
for(i = 0;i<nums.length;i++) {
sum = sum + nums[i];
}
console.log("和为:",sum)
}
addNumbers(1,2,3)
addNumbers(10,10,10,10,10)
复制代码
var arr:number[] = [12,13]
var[x,y] = arr // 将数组的两个元素赋值给变量 x 和 y
console.log(x) //12
console.log(y) //13
复制代码
var sites:string[] = new Array("Google","Runoob","Taobao","Facebook")
function disp(arr_sites:string[]) {
for(var i = 0;i<arr_sites.length;i++) {
console.log(arr_sites[i])
}
}
disp(sites);
复制代码
function disp():string[] {
return new Array("Google", "Runoob", "Taobao", "Facebook");
}
var sites:string[] = disp()
for(var i in sites) {
console.log(sites[i])
}
复制代码
enum Color {Red, Green, Blue}
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
console.log('enum',c,d,e) //0,1,2
复制代码
2.手动设置初始值 第一位未设置的默认0,后面递增.遇到有初始值的,后面的按照初始值+1.
enum Color {Red, Green=2, Blue}
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
console.log('enum',c,d,e) //0,2,3
复制代码
enum Color {Red, Green=2, Blue,Yellow=7 ,Dark}
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
let f: Color = Color.Yellow;
let g: Color = Color.Dark;
console.log('enum',c,d,e,f,g) //0 2 3 7 8
复制代码
3.属性获取
在赋予初始值的时候是以键值对的形式给的,那怎么拿到'键'呢?
enum Color {Red, Green=2, Blue,Yellow=7 ,Dark}
let c1: string = Color[0];
let c: Color = Color.Red;
let d1: string = Color[1];
let d: Color = Color.Green;
let e1: string = Color[2];
let e: Color = Color.Blue;
let f1: string = Color[3];
let f: Color = Color.Yellow;
let g1: string = Color[4];
let g: Color = Color.Dark;
console.log('enum',c1,c,d1,d,e1,e,f1,f,g1,g)
//Red 0 undefined 2 Green 3 Blue 7 undefined 8
复制代码
这里会出现undefined的缘由是由于[0]
这里面的0表明的是键所对应的值,由于没有一个键是1或者4(键值只存在0 2 3 7 8),因此1和4键对应的值是undefined 4. 设置初始值为字符串 假如设置的字符串不是最后一位,那后面的属性将没法设置默认值.咱们以前说过要递增+1,若是前一个是字符串,ts将没法处理初始化.
enum Color {Red, Green=2, Blue,Yellow='b' ,Dark='b'}
let g: Color = Color.Dark;
let test: string = Color['b'];
console.log('enum',g,test) //b undefined
复制代码
同时咱们,发现,并不能用字符串值拿到键位值,那么怎么拿到呢?通过查询资料得知,字符串赋值以后不进行反向映射.故拿不到对应键位值.
总结一下:
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,须要由具体的类去实现,而后第三方就能够经过这组抽象方法类调用。interface本质就是一个类的说明书,是约束条件
interface People {
name: string;
age: number;
height: number;
//?表示该属性可存在可不存在
weight?: number;
//能够添加任意属性,该属性名称为字符串类型,同时该属性的内容为任意
[propname: string]: any;
//函数返回类型为string
say(): string;
}
复制代码
相似的一个用法type
//type alias类型别名
type Lady={name:string,age:number}
const people2:Lady[]=[
{name:'zhangsan',age:11},
{name:'lisi',age:22},
]
class Madam{
name:string;
age:number
}
const people3:Madam[]=[
{name:'zhangsan',age:11},
{name:'lisi',age:22},
]
复制代码
这里存在一个和接口相似的定义type
interface User {
name: string
age: number
}
interface User {
sex: string
}
/* User 接口为 { name: string age: number sex: string } */
复制代码
// 基本类型别名
type Name = string
// 联合类型
interface Dog {
wong();
}
interface Cat {
miao();
}
type Pet = Dog | Cat
// 具体定义数组每一个位置的类型
type PetList = [Dog, Pet]
复制代码
接口继承及使用
//接口继承
interface NewPeople extends People {
done(): string;
}
const boy = {
name: "zhansan",
age: 18,
height: 160,
weight: 100,
sex: "女",
phone: 111111111,
say() {
return "i am zhangsan";
},
done() {
return "i can done";
},
};
const screenResume = (boy: People) => {
boy.age < 24 && boy.height > 170 && console.log(boy.name + "进入面试");
boy.age >= 24 || (boy.height < 170 && console.log(boy.name + "已被淘汰"));
};
const getResum = (boy: NewPeople) => {
console.log(boy.name + "年龄是" + boy.age);
console.log(boy.name + "身高是" + boy.height);
boy.weight && console.log(boy.name + "体重是" + boy.weight);
boy.sex && console.log(boy.name + "性别是" + boy.sex);
console.log(boy.say())
console.log(boy.done())
};
screenResume(boy);
getResum(boy);
复制代码
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine
}
// 方法
disp():void {
console.log("函数中显示发动机型号 : "+this.engine)
}
}
// 建立一个对象
var obj = new Car("XXSY1")
// 访问字段
console.log("读取发动机型号 : "+obj.engine)
// 访问方法
obj.disp()
复制代码
class People{
content="hi"
sayHello(){
return this.content
}
}
class Man1 extends People{
sayHello(){
//重写父类的方法时,可使用super关键字调用父类的方法或属性
return super.sayHello()+" 你好"
}
sayLove(){
return "i love you"
}
}
const goodess=new Man1()
console.log(goodess.sayHello())
console.log(goodess.sayLove())
复制代码
须要注意的是子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承
class Root {
str:string;
}
class Child extends Root {}
class Leaf extends Child {} // 多重继承,继承了 Child 和 Root 类
var obj = new Leaf();
obj.str ="hello"
console.log(obj.str)
复制代码
类继承后,子类能够对父类的方法从新定义,这个过程称之为方法的重写。 其中 super 关键字是对父类的直接引用,该关键字能够引用父类的属性和方法。
class PrinterClass {
doPrint():void {
console.log("父类的 doPrint() 方法。")
}
}
class StringPrinter extends PrinterClass {
doPrint():void {
super.doPrint() // 调用父类的函数
console.log("子类的 doPrint()方法。")
}
}
复制代码
class Person1{
private name:string;
public sayHello(){
//使用私有属性不报错
console.log(this.name+'say hello')
}
}
const person=new Person1()
//使用私有属性报错
person.name='ts'
console.log(person.name)
复制代码
class Person2{
public name:string;
constructor(name:string){
this.name=name;
}
}
class NewPerson2 extends Person2{
constructor(public age:number){
super("newts")
}
}
const person2=new Person2('ts')
console.log(person2.name)
const newperson=new NewPerson2(18)
console.log(newperson.name)
console.log(newperson.age)
class People4{
constructor(private _age:number){}
get age(){
return this._age
}
set age(newage:number){
this._age=newage+10
}
}
const onepeople=new People4(28)
console.log(onepeople.age)
onepeople.age=22
console.log(onepeople.age)
复制代码
static 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员能够直接经过类名调用。
//静态方法
class People5{
static sayLove(){
return 'I love you'
}
}
const onepeople2=new People5()
console.log(People5.sayLove())
复制代码
//只读属性
class People6{
public readonly _name:string
constructor(name:string){
this._name=name
}
}
const person6=new People6('ts')
console.log(person6._name)
复制代码
类能够实现接口,使用关键字 implements,并将其字段做为类的属性使用
class Man implements People {
//implement关键字表示该类Man受到接口People的约束
name = "zhangsan";
age = 11;
height = 180;
say() {
return "i can say";
}
}
复制代码
在定义函数,接口,类的时候,不预先指定具体的类型,而在使用的时候在去指定类型的一种特征 泛型的使用情景:
//函数泛型格式以下 函数方法名<T>(参数):返回值
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray<string>(3, 'x'); // ['x', 'x', 'x']
复制代码
其实泛型也能够理解为一种特殊的参数。例如函数的泛型的做用域就是整个函数做用域 函数也支持使用多个泛型
function identity <T, U>(value: T, message: U) : T {
console.log(message);
return value;
}
console.log(identity<Number, string>(68, "Semlinker"));
复制代码
相比以前定义的 identity 函数,新的 identity 函数增长了一个类型变量 U,但该函数的返回类型咱们仍然使用 T。若是咱们想要返回两种类型的对象该怎么办呢?针对这个问题,咱们有多种方案,其中一种就是使用元组,即为元组设置通用的类型
function identity <T, U>(value: T, message: U) : [T, U] {
return [value, message];
}
复制代码
更好的解决方案是使用泛型接口
interface Identities<V, M> {
value: V,
message: M
}
function identity<T, U> (value: T, message: U): Identities<T, U> {
console.log(value + ": " + typeof (value));
console.log(message + ": " + typeof (message));
let identities: Identities<T, U> = {
value,
message
};
return identities;
}
console.log(identity(68, "Semlinker"));
//输出
//68: number
//Semlinker: string
//{value: 68, message: "Semlinker"}
复制代码
在上述的Identities接口中,咱们引入了变量类型V和M,来进一步说明有效的字母均可以用于表示类型变量,以后,以后就能够将Identities接口做为identity函数的返回类型
在类中使用泛型,只须要在类名后面,使用<T,...>
的语法定义任意多个变量类型
interface GenericInterface<U> {
value: U
getIdentity: () => U
}
class IdentityClass<T> implements GenericInterface<T> {
value: T
constructor(value: T) {
this.value = value
}
getIdentity(): T {
return this.value
}
}
const myNumberClass = new IdentityClass<Number>(68);
console.log(myNumberClass.getIdentity()); // 68
const myStringClass = new IdentityClass<string>("Semlinker!");
console.log(myStringClass.getIdentity()); // Semlinker!
复制代码
这里以实例化myNumberClass为例分析其调用过程
IdentityClass
对象时,传入Number
类型和构造函数参数值68IdentityClass
类中,类型变量T
变成了Number
类型IdentityClass
实现了GenericInterface<T>
接口,此时T
表示Number
类型,所以等价于该类实现了GenericInterface<Number>
接口GenericInterface<U>
接口来讲,类型变量 U
也变成了 Number
。这里我有意使用不一样的变量名,以代表类型值沿链向上传播,且与变量名无关。举个例子,在处理字符串或者函数时,咱们回假设length
属性是可用的,因此当咱们直接输出arg.length
属性的时候,是有可能报错的 因此为了保证编译器知道T
必定含有length
属性,咱们须要让类型变量<T>
去extend
一个含有咱们所须要属性的接口
interface Length {
length: number;
}
function identity<T extends Length>(arg: T): T {
console.log(arg.length); // 能够获取length属性
return arg;
}
复制代码
<T extends Length>
这段代码就告诉编译器,咱们支持已经实现Length
接口的任何类型,以后,当咱们使用不含有length
属性的对象做为参数调用identity
函数时,Ts编译器就会提示想滚的错误信息
identity(68); // Error
// Argument of type '68' is not assignable to parameter of type 'Length'.(2345)
复制代码
此外,咱们还可使用 ,
号来分隔多种约束类型,好比:<T extends Length, Type2, Type3>
。而对于上述的 length 属性问题来讲,若是咱们显式地将变量设置为数组类型,也能够解决该问题,具体方式以下:
function identity<T>(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
// or
function identity<T>(arg: Array<T>): Array<T> {
console.log(arg.length);
return arg;
}
复制代码
在具体使用以前要先了解一些keyof
操做符,keyof
在TypeScript2.1版本引入,该操做符能够用于获取某种类型的全部键,其返回类型是联合类型
interface Person {
name: string;
age: number;
location: string;
}
type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // number | "length" | "push" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string | number
复制代码
经过 keyof
操做符,咱们就能够获取指定类型的全部键,以后咱们就能够结合前面介绍的 extends
约束,即限制输入的属性名包含在 keyof
返回的联合类型中。具体的使用方式以下:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
复制代码
在以上的 getProperty
函数中,咱们经过 K extends keyof T
确保参数 key
必定是对象中含有的键,这样就不会发生运行时错误。这是一个类型安全的解决方案,与简单调用 let value = obj[key]
不一样。
enum Difficulty {
Easy,
Intermediate,
Hard
}
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let tsInfo = {
name: "Typescript",
supersetOf: "Javascript",
difficulty: Difficulty.Intermediate
}
let difficulty: Difficulty =
getProperty(tsInfo, 'difficulty'); // OK
let supersetOf: string =
getProperty(tsInfo, 'superset_of'); // Error
//报错信息
Argument of type '"superset_of"' is not assignable to parameter of type
'"difficulty" | "name" | "supersetOf"'.(2345)
复制代码
使用步骤: