一、TypeScript中的配置文件
①生成tsconfig.json文件
npm install typescript -g
tsc init
②tsconfig.json文件的作用是typescript对应的编译配置文件
③运行tsc demo.ts会编译成demo.js文件
④只有单独输入tsc命令,后面不跟任何参数时,才会执行tsconfig里面的配置
ts-node demo.ts也会执行tsconfig里面的配置项
⑤compilerOptions前(或后)添加include指定想要编译的文件
"include": ["./demo.ts"]
同"files":["./demo.ts"]
也可以写exclude指定编译所有内容所要排除不编译的文件
"exclude": ["./demo.ts"]
⑥compilerOptions是编译属性配置项
"removeComments": true, //移除注释
"noImpliciAny": true, //不明确的指定any类型不行
"stictNummChecks": true, //强制检测Null类型,将null赋值给基础类型会报错
"rootDir": "./src", //指定输入文件的地址
"outDir": "./build", //指定编译后生成文件的地址
"incremental": true, //增量编译,以前编译过的内容不会再编译,只编译新增的文件
"allowJs": true, //是否对js文件也进行编译,把ES6语法编译为ES5语法文件
"checkJs": true, //允许对js文件像ts文件一样进行语法检测
二、联合类型和类型保护
interface Bird {
fly: boolean;
sing: () => {};
}
interface Dog {
fly:boolean;
bark: () => {};
}
//联合类型 - 属性只会取共有的属性
function trainAnimal(animal: Bird | Dog ) {
//1.类型断言 — 类型保护,规避typescript的潜在错误提示
if(animal.fly) {
(animal as Bird).sing();
}else{
(animal as Dog).bark()
}
}
function trainAnimalSecond(animal: Bird | Dog) {
//2.in语法 - 类型保护
if('sing' in animal) {
animal.sing();
}else{
animal.bark();
}
}
function add(first: string | number, second: string | number) {
//3.typeof 语法 - 类型保护
if(typeof first === 'string' || typeof second === 'string'){
return `${first}${second}`;
}
return first + second;
}
//只要class 才能被instanceof操作符使用,interface不能
class NumberObj {
count: number
}
function addSecond(first: object | NumberObj, second: object | NumberObj){
//4.instanceof 语法 - 类型保护
if(first instanceof NumberObj && second instanceof NumberObj){
return first.count + second.count
}
return 0;
}
三、Enum枚举类型
①初始化项目,生成package.json
npm init -y
②安装ts-node依赖
npm install ts-node -D
③package.json中添加命令
"dev": "ts-node ./demo.ts"
④安装typescript
npm install typescript --save
⑤Enum枚举类型应用
enum Status {
OFFLINE,
ONLINE,
DELETED
}
// const Status = {
// OFFLINE: 0,
// ONLINE: 1,
// DELETED: 2
// }
function getResult(status) {
if(status === Status.OFFLINE) {
return 'offline';
}else if(status === Status.ONLINE){
return 'online';
}else if(status === Status.DELETED){
return 'deleted';
}
return 'error'
}
const result = getResult(Status.OFFLINE);
console.log(result); //offline
四、函数泛型
//泛型 generic 泛指的类型
//T可以是任何类型的泛型
function join<T, P>(first: T, second: P) {
return `${first}${second}`;
}
join<number, string>(1, '1');
// T[]
function map<T>(params: Array<T>){
return params;
}
map<string>(['123']);
五、类中的泛型类型以及泛型类型
①类中的泛型类型
interface Item {
name: string;
}
class DataManager<T extends Item> {
constructor(private data: T[]) {}
getItem(index: number): string {
return this.data[index].name;
}
}
// const data = new DataManager<number>([1]);
// data.getItem(0);
const data = new DataManager([
{
name: 'dell'
}
])
class DataManager<T extends number | string> {
constructor(private data: T[]) {}
getItem(index: number): T {
return this.data[index]
}
}
// const data = new DataManager<string>([]);
const data = new DataManager<number>([]);
②泛型声明的type类型
// const func: <T>() => string = <T>() => {
// return '123'
// }
//如何使用泛型作为一个具体的类型注解
function hello<T>(param: T) {
return param
}
const func: <T>(param: T) => T = hello;
六、命名空间namespace
①tsconfig.json
"outDir": "./dist",
"rootDir": "./src",
②index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script src='./dist/page.js'></script>
</head>
<body>
<script>
new Home.Page();
</script>
</body>
</html>
③src->page.ts: Home命名空间中,export暴露出要用的page,index.html中就可以使用new Home.page();其它方法不使用则不暴露
namespace Home {
class Header {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Header';
document.body.appendChild(elem);
}
}
class Content {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Content';
document.body.appendChild(elem);
}
}
class Footer {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Footer';
document.body.appendChild(elem);
}
}
export class Page {
constructor() {
new Header();
new Content();
new Footer();
}
}
}
- 拆分页面和组件多个命名空间
①tsconfig.json
"outFile": "./dist/page.js" , //把所有要输出的文件联合起来输出一个单一的文件
此时会有报错,因为设置了outFile后只支持amd或system的规范,不支持commenjs的规范了
"module": "amd",
②index.html不变
③src->page.ts依赖conponents.ts
//依赖声明
///<reference path="./components.ts" />
namespace Home {
export class Page {
user: Components.User = {
name: 'dell'
}
constructor() {
new Components.Header();
new Components.Content();
new Components.Footer();
}
}
}
④src->components.ts暴露给page.ts所需要的方法和子命名空间
namespace Components {
//子的命名空间
export namespace SubComponents {
export class Test {}
}
export interface User {
name: string;
}
export class Header {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Header';
document.body.appendChild(elem);
}
}
export class Content {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Content';
document.body.appendChild(elem);
}
}
export class Footer {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Footer';
document.body.appendChild(elem);
}
}
}
⑤问题:page.ts中依赖的Components命名空间必须在打开其它文件后才可以追溯到
七、import对应的模块化
①src->components.ts:export暴露三个变量
export class Header {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Header';
document.body.appendChild(elem);
}
}
export class Content {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Content';
document.body.appendChild(elem);
}
}
export class Footer {
constructor() {
const elem = document.createElement('div');
elem.innerText = 'This is Footer';
document.body.appendChild(elem);
}
}
②src->page.ts:import导入components的变量,export default最终要用到的Page
import { Header, Content, Footer } from './components'
export default class Page {
constructor() {
new Header();
new Content();
new Footer();
}
}
③问题:'define' is not defined,原因是现在打包生成的文件是amd规范,浏览器不识别define()语法
④index.html中引入require.js,帮助识别define()语法;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script src='https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js'></script>
<script src='./dist/page.js'></script>
</head>
<body>
<script>
require(['page'], function(page) {
new page.default()
})
</script>
</body>
</html>
八、使用parcel打包TS代码
①安装parcel@next打包工具
npm install parcel@next -D
②package.json中修改test命令
"test": "parcel ./index.html"
③运行npm run test,开启一个服务器地址http://localhost:1234
九、描述文件中的全局类型
①index.html中引用jquery的CDN文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script src='https://cdn.bootcss.com/jquery/3.4.1/jquery.js'></script>
<script src='./page.ts'></script>
</head>
<body>
</body>
</html>
②jquey语法在typescript中没有注解,需要写一个类型定义文件,打通ts文件和js文件之间的鸿沟
③src->page.ts:使用jqurey写js语句
// $(function() {
// alert(123);
// })
$(function() {
$('body').html('<div>123</div>')
})
④src->jquery.d.ts:类型注解文件
//declare 声明 - 定义全局变量
// declare var $ : (param: () => void) => void;
//declare 声明 - 定义全局函数
declare function $(param: () => void): void;
//函数重载:参数不同,允许对一个函数名字写多个函数声明
declare function $(param: string): {
html: (html: string) => {}
}
问题:jquery函数返回的应该也是一个jqury对象,不能指定为{}
//定义全局函数
interface JqueryInstance {
html: (html: string) => JqueryInstance;
}
declare function $(readyFunc: () => void): void;
declare function $(selector: string): JqueryInstance;
使用 接口语法 写函数重载
//定义全局函数
interface JqueryInstance {
html: (html: string) => JqueryInstance;
}
//使用interface的语法,实现函数重载
interface JQuery {
(readyFunc: () => void): void;
(selector: string): JqueryInstance;
}
declare var $: Jquery;
- 如何对对象进行类型定义,以及对类进行类型定义,以及命名空间的嵌套
①page.ts:在使用$('body')时,相当于执行了new $.fn.init();
$(function() {
$('body').html('<div>123</div>');
new $.fn.init(); //构造函数 才能用new语法
})
②jquery.d.ts
//定义全局函数
interface JqueryInstance {
html: (html: string) => JqueryInstance;
}
//函数重载
declare function $(readyFunc: () => void): void;
declare function $(selector: string): JqueryInstance;
//如何对对象进行类型定义,以及对类进行类型定义,以及命名空间的嵌套
declare namespace $ { //$ 是命名空间
namespace fn { //fn 是命名空间
class init {} //init 是构造函数
}
}
十、模块代码的类型描述文件
①安装jquery
npm install jquery --save
import引用jquery,会提示报错,找不到jquery module
import $ from 'jquery';
$(function() {
$('body').html('<div>123</div>');
new $.fn.init(); //构造函数 才能用new语法
})
③jquery.d.ts: 通过module定义一个jquery的模块,定义关于$混合类型的内容,最终export导出要使用的$
//ES6 模块化
declare module 'jquery' {
//定义全局函数
interface JqueryInstance {
html: (html: string) => JqueryInstance;
}
//$ 混合类型 - 不必再写declare, 直接写function即可
function $(readyFunc: () => void): void;
function $(selector: string): JqueryInstance;
namespace $ { //$ 是命名空间
namespace fn { //fn 是命名空间
class init {} //init 是构造函数
}
}
export = $;
}
十一、泛型中keyof语法的使用
interface Person {
name: string;
age: number;
gender: string;
}
class Teacher {
constructor(private info: Person) {}
getInfo(key: string){
//类型保护
if(key === 'name' || key === 'age' || key === 'gender'){
return this.info[key];
}
}
}
const teacher = new Teacher({
name: 'dell',
age: 18,
gender: 'male'
})
const test = teacher.getInfo('name');
console.log(test)
问题:test的可能类型会是string | number | underfind,是因为传任何值给getInfo方法时,key值不定
typescript不会深度分析,传入的是不是name类型,如果是则值必须是string类型;传入的是age类型,值必须是number类型
解决:通过泛型结合keyof语法
interface Person {
name: string;
age: number;
gender: string;
}
//第一次循环
//T extends 'name'
//type T = 'name'
//key: 'name'
//Person['name']; //string
//第二次循环
//T extends 'age'
//type T = 'age'
//key: 'age'
//Person['age']; //number
class Teacher {
constructor(private info: Person) {}
getInfo<T extends keyof Person>(key: T): Person[T]{
return this.info[key];
}
}
const teacher = new Teacher({
name: 'dell',
age: 18,
gender: 'male'
})
const test = teacher.getInfo('name');
console.log(test)
越是迷茫、浮躁的时候,保持冷静和耐心,尤为重要