这样学TS,迟早进大厂系列(第二期)

江左梅郎: 一个对开发技术特别执着的程序员,对移动开发有着独到的见解和深入的研究,有着多年的H5开发经验,对NativeApp、HybridApp、WebApp开发有着独到的见解和深入的研究, 除此之外还精通 JavaScript、AngularJS、 NodeJS 、Ajax、jQuery、Cordova、Vue、React Native等多种Web前端技术及Java、PHP等服务端技术。


TS从初级到高级 第一期.

TS从初级到高级 第二期.

TS从初级到高级 第三期.

TS从初级到高级 第四期.

TS从初级到高级 第五期.

TS从初级到高级 第六期.

TS从初级到高级 第七期.
更新中…


初学者玩转 TypeScript系列,总计 10 期,本文为第 2 期,点赞、收藏、评论、关注、三连支持!

对于初学者来说,学习编程最害怕的就是,

那么,Typescript 是不是很难?

首先,我可以肯定地告诉你,你的焦虑是多余的。新手对学习新技术有很强的排斥心理,主要是因为基础不够扎实,然后自信心不够强。

1. 变量声明和解构?

  • TS中变量声明和解构和ES6一样

  • 详见 ES6 相关知识

2. 接口的基本使用

  • 什么是接口类型?

  • 和 number,string,boolean,enum 这些数据类型一样

  • 接口也是一种类型, 也是用来约束使用者的

* */
// 定义一个接口类型
interface FullName{
    firstName:string
    lastName:string
}
let obj = {
    firstName:'Jonathan',
    lastName:'Lee'
    // lastName:18
};
// 需求: 要求定义一个函数输出一个人完整的姓名
// 这个人的姓必须是字符串, 这个人的名也必须是一个字符
function say({firstName, lastName}:FullName):void {
    console.log(`我的姓名是:${firstName}_${lastName}`);
}
say(obj);

 

3.可选属性和索引签名

  • 定义一个接口
interface FullName{
    firstName:string
    lastName:string
    middleName?:string
    [propName:string]:any
}

 
  • 需求: 如果传递了 middleName 就输出完整名称, 如果没有传递middleName, 那么就输出 firstName 和 lastName
function say({firstName, lastName, middleName}:FullName):void {
    // console.log(`我的姓名是:${firstName}_${lastName}`);
    if(middleName){
        console.log(`我的姓名是:${firstName}_${middleName}_${lastName}`);
    }else{
        console.log(`我的姓名是:${firstName}_${lastName}`);
    }
}
// 注意点: 如果使用接口来限定了变量或者形参, 那么在给变量或者形参赋值的时候,
// 赋予的值就必须和接口限定的一模一样才可以, 多一个或者少一个都不行
// say({firstName:'Jonathan'});
// say({firstName:'Jonathan', lastName:'Lee', middleName:"666"});
// 注意点: 但是在企业开发中可以多一个也可能少一个
// 少一个或多个怎么做? 可选属性
// say({firstName:'Jonathan', lastName:'Lee', middleName:"666"});
// say({firstName:'Jonathan', lastName:'Lee'});
// 多一个或者多多个怎么做? 如果绕开TS检查
// 方式一: 使用类型断言
// say({firstName:'Jonathan', lastName:'Lee', middleName:"666", abc:'abc'} as FullName);
// 方式二: 使用变量
// let obj = {firstName:'Jonathan', lastName:'Lee', middleName:"666", abc:'abc'};
// say(obj);
// 方式三: 使用索引签名
say({firstName:'Jonathan', lastName:'Lee', middleName:"666", abc:'abc', 123:123, def:"def"});

 

4. 函数接口和混合类型接口

  • 函数接口
  • 我们除了可以通过接口来限定对象以外, 我们还可以使用接口来限定函数
/*
interface SumInterface {
    (a:number, b:number):number
}
let sum:SumInterface = function (x:number, y:number):number {
    return x + y;
}
let res = sum(10, 20);
console.log(res);
 */
// 混合类型接口
// 约定的内容中既有对象属性, 又有函数
// 要求定义一个函数实现变量累加
/*
let count = 0; // 会污染全局空间
function demo() {
    count++;
    console.log(count);
}
demo();
demo();
demo();
 */
/*
let demo = (()=>{ // 使用闭包确实可以解决污染全局空间的问题, 但是对于初学者来说不太友好
    let count = 0;
    return ()=>{
        count++;
        console.log(count);
    }
})();
demo();
demo();
demo();
 */
// 在JS中函数的本质是什么? 就是一个对象
// let demo = function () {
//     demo.count++;
// }
// demo.count = 0;
// demo();
// demo();
// demo();
interface CountInterface {
    ():void
    count:number
}
let getCounter = (function ():CountInterface {
    /*
    CountInterface接口要求数据既要是一个没有参数没有返回值的函数
                              又要是一个拥有count属性的对象
    fn作为函数的时候符合接口中函数接口的限定 ():void
    fn作为对象的时候符合接口中对象属性的限定  count:number
    * */
    let fn = <CountInterface>function () {
        fn.count++;
        console.log(fn.count);
    }
    fn.count = 0;
    return fn;
})();
getCounter();
getCounter();
getCounter();

 

5. 接口的继承

  • 接口的继承
  • TS中的接口和JS中的类一样是可以继承的
interface LengthInterface {
    length:number
}
interface WidthInterface {
    width:number
}
interface HeightInterface {
    height:number
}
interface RectInterface extends LengthInterface,WidthInterface,HeightInterface {
    // length:number
    // width:number
    // height:number
    color:string
}
let rect:RectInterface = {
    length:10,
    width:20,
    height:30,
    color:'red'
}

 

6. TypeScript 函数

  • TS中的函数
  • TS中的函数大部分和JS相同

// 命名函数
function say1(name) {
    console.log(name);
}
// 匿名函数
let say2 = function (name) {
    console.log(name);
}
// 箭头函数
let say3 = (name) => {
    console.log(name);
}

 
// 命名函数
function say1(name:string):void {
    console.log(name);
}
// 匿名函数
let say2 = function (name:string):void {
    console.log(name);
}
// 箭头函数
let say3 = (name:string):void =>{
    console.log(name);
}

 

7. 函数的声明与重载

// TS函数完整格式
// 在TS中函数的完整格式应该是由函数的定义和实现两个部分组成的
/*
// 定义一个函数
let AddFun:(a:number, b:number)=>number;
// 根据定义实现函数
AddFun = function (x:number, y:number):number {
    return x + y;
};
let res = AddFun(10, 20);
console.log(res);
*/
/*
// 一步到位写法
let AddFun:(a:number, b:number)=>number =
function (x:number, y:number):number {
    return x + y;
};
let res = AddFun(20, 20);
console.log(res);
*/
/*
// 根据函数的定义自动推导对应的数据类型
let AddFun:(a:number, b:number)=>number =
    function (x, y) {
        return x + y;
    };
let res = AddFun(20, 20);
console.log(res);
*/
// TS函数声明
/*
// 先声明一个函数
type AddFun = (a:number, b:number)=>number;
// 再根据声明去实现这个函数
// let add:AddFun = function (x:number, y:number):number {
//     return x + y;
// };
let add:AddFun = function (x, y) {
    return x + y;
};
let res = add(30, 20);
console.log(res);
*/
// TS函数重载
// 函数的重载就是同名的函数可以根据不同的参数实现不同的功能
/*
function getArray(x:number):number[] {
    let arr = [];
    for(let i = 0; i <= x; i++){
        arr.push(i);
    }
    return arr;
}
function getArray(str:string):string[] {
    return str.split('');
}
 */
// 定义函数的重载
function getArray(x:number):number[];
function getArray(str:string):string[];
// 实现函数的重载
function getArray(value:any):any[] {
    if(typeof value === 'string'){
        return value.split('');
    }else{
        let arr = [];
        for(let i = 0; i <= value; i++){
            arr.push(i);
        }
        return arr;
    }
}
// let res = getArray(10);
let res = getArray('www.it666.com');
console.log(res);

 

8. 泛型

  • 什么是泛型?
  • 在编写代码的时候我们既要考虑代码的健壮性, 又要考虑代码的灵活性和可重用性
  • 通过TS的静态检测能让我们编写的代码变得更加健壮, 但是在变得健壮的同时却丢失了灵活性和可重用性
    所以为了解决这个问题TS推出了泛型的概念
  • 通过泛型不仅可以让我们的代码变得更加健壮, 还能让我们的代码在变得健壮的同时保持灵活性和可重用性
// 需求: 定义一个创建数组的方法, 可以创建出指定长度的数组, 并且可以用任意指定的内容填充这个数组
/*
let getArray = (value:number, items:number = 5):number[]=>{
    return new Array(items).fill(value);
};
// let arr = getArray(6, 3);
let arr = getArray("abc", 3); // 报错
console.log(arr);
 */
/*
let getArray = (value:any, items:number = 5):any[]=>{
    return new Array(items).fill(value);
};
// let arr = getArray("abc", 3);
let arr = getArray(6, 3);
// console.log(arr);
// 当前存储的问题:
// 1.编写代码没有提示, 因为TS的静态检测不知道具体是什么类型
// 2.哪怕代码写错了也不会报错, 因为TS的静态检测不知道具体是什么类型
let res = arr.map(item=>item.length); // ['abc', 'abc', 'abc'] => [3, 3, 3]
console.log(res);
 */
// 需求:要有代码提示, 如果写错了要在编译的时候报错
let getArray = <T>(value:T, items:number = 5):T[]=>{
    return new Array(items).fill(value);
};
// let arr = getArray<string>('abc');
// let arr = getArray<number>(6);
// 注意点: 泛型具体的类型可以不指定
//         如果没有指定, 那么就会根据我们传递的泛型参数自动推导出来
let arr = getArray('abc');
// let arr = getArray(6);
let res = arr.map(item=>item.length);
console.log(res);

 

9. 泛型约束

  • 什么是泛型约束?
  • 默认情况下我们可以指定泛型为任意类型
    但是有些情况下我们需要指定的类型满足某些条件后才能指定
    那么这个时候我们就可以使用泛型约束
// 需求: 要求指定的泛型类型必须有Length属性才可以
interface LengthInterface{
    length:number
}
let getArray = <T extends LengthInterface>(value:T, items:number = 5):T[]=>{
    return new Array(items).fill(value);
};
let arr = getArray<string>('abc');
// let arr = getArray<number>(6);
let res = arr.map(item=>item.length);

 

码字不易,在线求个三连支持。

大家记得收藏前,先点个赞哦!好的文章值得被更多人看到。

最后,再多一句,粉丝顺口溜,关注江哥不迷路,带你编程上高速。

版权所有,请勿转载,转载请联系本人授权


支付宝生态技术学习交流群

posted @ 2021-08-17 09:48  江咏之  阅读(91)  评论(0编辑  收藏  举报