執行命令javascript
tsc --init
複製代碼
生成tsconfig.json
文件,也就是TS
的編譯配置文件。html
{
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}
複製代碼
編譯TS
命令,直接指定編譯某個ts文件的時候並不會使用tsconfig.json
中的內容,只有直接運行tsc
時,纔會走tsconfig.json
中的配置java
tsc dome.ts
複製代碼
只有直接運行tsc
時,纔會走tsconfig.json
中的配置。在未配置tsconfig.json
的狀況下,會執行編譯全部的ts
文件node
tsc // 在未配置tsconfig.json的狀況下,會執行編譯全部的ts文件
複製代碼
tsc
命令會找tsconfig.json
,react
"include": ["./demo.ts"], // 指定只編譯demo.ts文件
"exclude": ["./demo.ts"], // 排除編譯demo.ts文件,就不會編譯demo.ts
"files": ["./demo.ts"], // files與include功能相同
"removeComments": true // 編譯中移除註釋
複製代碼
也能夠寫成jquery
"include": ["src/**/*"], // ** 表明任何目錄,* 表明任何文件
複製代碼
參考文檔: tsconfig-jsonwebpack
compilerOptions
字面意思:就是編譯過程當中的一些屬性或配置。git
"compilerOptions": {
"removeComments": true, // 編譯中移除註釋
"noImplicitAny": false, // 不要求顯示的設置any,false就是能夠,這樣變量不定義類型也不會報錯。默認true
"strictNullChecks": false, // 強制檢查null類型。默認true。不然編譯會報錯。
}
複製代碼
如es6
const children: string = null // 不容許把null複製給其餘基礎類型 strictNullChecks設置爲false則不會報錯,編譯也不會報錯。
複製代碼
"rootDir": "./src", // 輸入地址
"outDir": "./build", // 生成地址
複製代碼
tsconfig.tsbuildinfo
文件,用來記錄上次編譯過程當中的信息,再次編譯的時候就會和上一次作比對。是一個增量式的配置項。"incremental": true, // 增量編譯
複製代碼
"target": "es5", // 將代碼編譯成es5
"allowJs": true, // 是否容許對js項也進行編譯
複製代碼
編譯前:github
export const name = 'dell'
複製代碼
編譯後
"use strict"
Object.defineProperty(exports, "__esModule", {value: true})
exports.name = 'dell'
複製代碼
"checkJs": true, // 對js文件進行語法檢測
複製代碼
sourceMap
文件,***.js.map
"sourceMap": true,
複製代碼
"noUnusedLocals": true,
複製代碼
"noUnusedParameters": true,
複製代碼
參考文檔:編譯選項
Unin type
和類型保護用類型保護解決聯合類型遇到的問題
as
interface Bird {
fly: boolean,
sing: () => {},
}
interface Dog {
fly: boolean,
bark: () => {},
}
// 聯合類型 animal: Bird | Dog
function trainAnimal (animal: Bird | Dog) {
// 類型保護 sing和bark是獨有的屬性
// 類型斷言 (animal as Bird) 傳入的animal是Bird的時候
if (animal.fly) { // Bird纔會飛true
(animal as Bird).sing() // as 斷言
} else {
(animal as Dog).bark()
}
}
複製代碼
in
語法function trainAnimalSecond (animal: Bird | Dog) {
if ('sing' in animal) {
animal.sing()
} else {
animal.bark()
}
}
複製代碼
typeof
語法function add (first: string | number, second: string | number) {
if (typeof first === 'string' || typeof second === 'string') {
return `${first}${second}`
}
return first + second
}
複製代碼
instanceof
語法,只有爲class
類的時候纔可使用,interface
不能用instanceof
class NumberObj {
public count: number
}
function addSecond (first: object | NumberObj, second: object | NumberObj) {
if (first instanceof NumberObj && second instanceof NumberObj) {
return first.count + second.count
}
return 0
}
複製代碼
Enum
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';
} else {
return 'error';
}
}
const result = getResult(Status.OFFLINE);
console.log(result); // online
複製代碼
ts
來寫枚舉enum Status {
OFFLINE,
ONLINE,
DELETED
}
// 枚舉默認值爲 0 1 2
console.log(Status.OFFLINE); // 0
console.log(Status.ONLINE); // 1
console.log(Status.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';
} else {
return 'error';
}
}
const result = getResult(Status.OFFLINE);
const result1 = getResult(0);
console.log(result); // offline
console.log(result1); // offline
複製代碼
輸出結果,依舊不變。
改變offline
的枚舉值
enum Status {
OFFLINE = 1,
ONLINE,
DELETED
}
console.log(Status.OFFLINE); // 1
console.log(Status.ONLINE); // 2
console.log(Status.DELETED); // 3
複製代碼
enum Status {
OFFLINE, // 默認從0 開始
ONLINE = 4,
DELETED // 從4開始加1
}
console.log(Status.OFFLINE); // 0
console.log(Status.ONLINE); // 4
console.log(Status.DELETED); // 5
複製代碼
枚舉類型還能夠反查結果(反向映射),以下:
enum Status {
OFFLINE,
ONLINE,
DELETED
}
console.log(Status[0]); // OFFLINE
複製代碼
enum
是一個更靈活的數據結構。
使用場景:
console.log(Status[4])
爲ONLINE
小插曲:在安裝typescirpt
的時候居然報了以下錯誤,緣由是項目的name
也是typescript
,修改以後便可正常安裝。
npm ERR! code ENOSELF
npm ERR! Refusing to install package with name "typescript" under a package
npm ERR! also called "typescript". Did you name your project the same
npm ERR! as the dependency you're installing? npm ERR! npm ERR! For more information, see: npm ERR! <https://docs.npmjs.com/cli/install#limitations-of-npms-install-algorithm> 複製代碼
{
"name": "typescript",
"version": "1.0.0",
"description": "",
"main": "index.js",
"devDependencies": {
"ts-node": "^8.6.2"
},
"scripts": {
"dev": "ts-node ./src/enum.ts"
},
"keywords": [],
"author": "",
"license": "ISC"
}
複製代碼
泛型generic
:泛指的類型,寫法<>
針對不肯定的類型就能夠用泛型語法,在使用的時候再指定具體的對應值。
示例1
// <ABC> 定義名字爲ABC的泛型,兩個傳入的參數都要求爲同一類型
function join<ABC>(first: ABC, second: ABC) {
return `${first}${second}`
}
// 在使用時給ABC指定類型,定義類型都爲string,傳入的值就必須爲string類型
join<string>('1','2')
複製代碼
以下寫法,則沒法作到兩個參數傳入值必須爲同一類型的要求。
function join(first: string | number, second: string | number) {
return `${first}${second}`
}
join('1',2)
複製代碼
示例2
// function map<ABC> (params: Array<ABC>) {
function map<ABC> (params: ABC[]) {
return params
}
map<string>(['1', '2', '3'])
複製代碼
常見用T
來代替ABC
,也就是Type
的簡寫
// function map<T> (params: Array<T>) {
function map<T> (params: T[]) {
return params
}
map<string>(['1', '2', '3'])
複製代碼
咱們還能夠定義兩個泛型或多個泛型
function join<T, P>(first: T, second: P) {
return `${first}${second}`;
}
join<string, number>('1', 2); // 顯式聲明類型
join<('1', 2) // 不寫類型則會默認推斷
複製代碼
不寫類型則會默認推斷(類型推斷),以下圖:
聲明返回類型也用T
這個泛型,以下:
function anotherJoin<T>(first: T, second: T): T {
return first;
}
anotherJoin<string>('1', '2');
複製代碼
泛型和普通的類型使用基本是同樣的。使用的時候須要在函數前用<>
作一個聲明。
Demo1
class DataManager<T> {
constructor(private data: T[]) {}
getItem(index: number): T {
return this.data[index];
}
}
const data = new DataManager<number>([2]);
data.getItem(0);
複製代碼
Demo2: 讓泛型繼承某一屬性
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([{ name: '2' }]);
data.getItem(0);
複製代碼
Demo3: 泛型是number
或string
,<T extends number | string>
class DataManager<T extends number | string> {
constructor(private data: T[]) {}
getItem(index: number): T {
return this.data[index];
}
}
const data = new DataManager<number>([2])
複製代碼
Demo4: 如何使用泛型做爲一個具體的類型註解
// 泛型還能夠當作type的聲明
function hello<T>(params: T) {
return params
}
const func:<T>(param: T) => T = hello
複製代碼
過多的全局變量必定會讓頁面變的不可維護。
編譯前:
// 把全部東西都放到Home這樣的命名空間中,防止Header、Content、Footer都暴露在全局環境中
namespace Home {
class Header {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Header';
document.body.appendChild(element);
}
}
class Content {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Content';
document.body.appendChild(element);
}
}
class Footer {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Footer';
document.body.appendChild(element);
}
}
export class Page { // 導出Page
constructor() {
new Header();
new Content();
new Footer();
}
}
}
new Home.Page();
複製代碼
編譯後:
// 把全部東西都放到Home這樣的命名空間中
var Home;
(function (Home) {
var Header = /** @class */ (function () {
function Header() {
var element = document.createElement('div');
element.innerHTML = 'This is Header';
document.body.appendChild(element);
}
return Header;
}());
var Content = /** @class */ (function () {
function Content() {
var element = document.createElement('div');
element.innerHTML = 'This is Content';
document.body.appendChild(element);
}
return Content;
}());
var Footer = /** @class */ (function () {
function Footer() {
var element = document.createElement('div');
element.innerHTML = 'This is Footer';
document.body.appendChild(element);
}
return Footer;
}());
var Page = /** @class */ (function () {
function Page() {
new Header();
new Content();
new Footer();
}
return Page;
}());
Home.Page = Page; // 將Page方法暴露出來
})(Home || (Home = {}));
new Home.Page();
複製代碼
這種寫法可讓咱們盡少的聲明全局變量,把一組相關的內容封裝到一塊兒,對外提供統一的接口。
// tsconfig.json
"outFile": "./build/page.js", // 將多個ts文件統一輸出到一個js文件中./build/page.js文件中
"module": "amd"
複製代碼
將文件拆成page.ts
和components.ts
// components.ts
namespace Components {
// 子命名空間
export namespace SubComponents {
export class Test{}
}
// 導出接口
export interface User {
name: string;
}
export class Header {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Header';
document.body.appendChild(element);
}
}
export class Content {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Content';
document.body.appendChild(element);
}
}
export class Footer {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Footer';
document.body.appendChild(element);
}
}
}
複製代碼
// page.ts
依賴的聲明,namespace之間相互引用的聲明,用///表示
/// <reference path='./components.ts' />
namespace Home {
export class Page {
user: Components.User = {
name: 'fruit'
}
constructor() {
new Components.Header();
new Components.Content();
new Components.Footer();
}
}
}
new Home.Page();
複製代碼
amd語法瀏覽器是不支持的
// components.ts
export class Header {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Header';
document.body.appendChild(element);
}
}
export class Content {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Content';
document.body.appendChild(element);
}
}
export class Footer {
constructor() {
const element = document.createElement('div');
element.innerHTML = 'This is Footer';
document.body.appendChild(element);
}
}
複製代碼
import 模塊引入(es6用法)
// page.ts
import { Header, Content, Footer } from './components';
class Page {
constructor() {
new Header();
new Content();
new Footer();
}
}
new Page();
複製代碼
參考文檔:
zhuanlan.zhihu.com/p/25107397?…
Parcel
:是和webpack
相似的打包工具,不須要作過多配置,使用起來相對簡單。
npm init -y
複製代碼
tsc --init
複製代碼
parcel : github.com/parcel-bund…
npm install parcel@next -D
複製代碼
// package.json
"scripts": {
"test": "parcel ./src/index.html"
},
複製代碼
運行
npm run test
複製代碼
在瀏覽器訪問
http://localhost:1234/
便可查看相關運行結果
類型定義文件***.d.ts
如何在.d.ts
文件裏對全局函數和全局變量進行定義
// jquery.d.ts
// 定義全局變量
declare var $: (param: () => void) => void;
// 定義全局函數
declare function $(param: () => void): void;
// 容許一個函數屢次定義。函數的重載,根據傳入參數的不一樣變化
declare function $(params: string): {
html: (html: string) => {}
}
複製代碼
寫法優化
// 定義全局函數
interface JqueryInstance {
html: (html: string) => JqueryInstance;
}
// 函數重載
declare function $(readyFunc: () => void): void;
declare function $(selector: string): JqueryInstance;
複製代碼
使用$就不會報錯
$(function() {
$('div').html('<div>123</div>');
});
複製代碼
爲何咱們要安裝或本身寫類型定義文件,幫助咱們的ts
文件,理解js
文件或js
庫中的內容。好比$
。
**.d.ts
爲類型描述文件或類型定義文件
使用interface實現函數重載
// $只是不一樣的函數,只是對函數重載的時候,能夠用下面的語法
interface JQuery {
(readyFunc: () => void): void
(selector: string): JqueryInstance
}
declare var $: JQuery;
複製代碼
// 如何對對象進行類型定義,以及如何對類進行類型定義,以及命名空間的嵌套
// 既讓$是函數,又讓$是對象,就能夠用下面的語法
declare namespace $ { // 在全局有對象,能夠用namespace來構建這個對象
namespace fn {
class init {}
}
}
// 引入外部的庫,TS沒法識別,咱們就能夠用全局聲明內容的語法,讓ts可以理解,$裏都有哪些內容
$(function() {
$('div').html('<div>123</div>');
new $.fn.init();
});
複製代碼
引入外部的庫,TS沒法識別,咱們就能夠用全局聲明內容的語法,讓TS可以理解,$裏都有哪些內容
參考文檔:TypeScript error: Property 'X' does not exist on type 'Window'
當咱們使用window
時,好比 let a = window.a
,將a
掛載到window
下,此時TS
會報以下錯誤:
TypeScript error: Property 'a' does not exist on type 'Window'. TS2339
複製代碼
以下,使用type
定義依舊無效
type Window = {
a: any
}
let a = window.a;
複製代碼
解決方法
declare const window: any;
let a = window.a;
複製代碼
es六、commonjs、UMD
等在TS
中如何定義
npm install jquery --save
複製代碼
import $ from 'jquery'
複製代碼
報以下錯誤
此時咱們須要模塊化的描述文件。ES6
模塊化的類型註解文件,就是這麼寫出來的。Commonjs
UMD
等寫法和ES6
寫法稍有不一樣,可查閱相關資料。
// jquery.d.ts
// ES6 模塊化
declare module 'jquery' {
interface JqueryInstance {
html: (html: string) => JqueryInstance;
}
// 混合類型
function $(readyFunc: () => void): void;
function $(selector: string): JqueryInstance;
namespace $ {
namespace fn {
function init(): void;
}
}
// 導出
export = $;
}
複製代碼
這樣使用$就不會報錯了
import $ from 'jquery';
$(function() {
$('div').html('<div>123</div>');
new $.fn.init();
});
複製代碼
keyof
語法的使用interface Persone {
name: string;
age: number;
gender: string;
}
class Student {
constructor(private info: Persone) {}
getInfo(key: string) {
return this.info[key]; // 咱們沒法肯定key的值
}
}
const student1 = new Student({
name: 'fruit',
age: 18,
gender: 'male'
});
const studentName = student1.getInfo('name');
複製代碼
studentName
的類型返回的爲any
key
值是不安全的,當傳入的值爲
name
、
age
、
gender
以外的值時,就會返回
undefined
,所以咱們須要類型保護來解決這個問題。
修改寫法:但不夠好,傳入這三個值以外的值是,仍是會返回undefined
getInfo(key: string) {
if (key === 'name' || key === 'age' || key === 'gender') {
return this.info[key];
}
}
複製代碼
泛型結合keyof
來寫
type T = 'name'
key: 'name'
Person1['name']
type T = 'age'
key: 'age'
Person1['age']
type T = 'gender'
key: 'gender'
Person1['gender']
複製代碼
interface Person1 {
name: string;
age: number;
gender: string;
}
class Student {
constructor(private info: Person1) {}
getInfo<T extends keyof Person1>(key: T): Person1[T] {
return this.info[key];
}
}
const student1 = new Student({
name: 'fruit',
age: 18,
gender: 'male'
});
const studentName = student1.getInfo('hello'); // 不能傳hello,只能是name、age、gender
複製代碼
當咱們定義一個類型的時候,可讓類型不是string、number等基礎類型,也能夠是interface、{}對象等複雜類型,咱們的類型甚至是固定的字符串,如:
type T = 'name'
,類型的值就是一個字符串。
type A = 'NAME'
const a: A = 'bc'
複製代碼
報以下錯誤:
// 這樣就不報錯,變量的值必須和type中'NAME'字符串同樣的東西
type A = 'NAME'
const a: A = 'NAME'
複製代碼
所以,類型也能夠是一個字符串。正是由於這個原理,咱們才能夠用keyof
語法,結合泛型,實現上述效果(只能傳遞對應的key)。若是有一個類,裏面有一個對象,咱們想根據index、或key值獲取對象裏的某項內容時,又想要推斷出正確的返回類型,就能夠用相似這樣的語法來解決<T extends keyof Person1>(key: T): Person1[T]