内容简介:TypeScript 是 JavaScript 的类型的超集,它可以编译成纯 JavaScript。编译出来的 JavaScript 可以运行在任何浏览器上。TypeScript 编译工具可以运行在任何服务器和任何系统上。TypeScript 是开源的。以下内容均出自于TS入门教程以及Ts 官网的一些内容,没有基础的小伙伴直接看打了:star:️的内容即可。
TypeScript 是 JavaScript 的类型的超集,它可以编译成纯 JavaScript。编译出来的 JavaScript 可以运行在任何浏览器上。TypeScript 编译 工具 可以运行在任何服务器和任何系统上。TypeScript 是开源的。
以下内容均出自于TS入门教程
以及Ts 官网的一些内容,没有基础的小伙伴直接看打了:star:️的内容即可。
尝试
看了之后怎么搭个环境写一写?
mkdir demo cd demo touch 1.ts 复制代码
打开vscode,打开控制台,切换到问题 tab
欧了,开始尝试 ts 吧
:star:️基础类型
└boolean
let isDone: boolean = false; // 使用构造函数 Boolean 创造的对象不是布尔值 复制代码
└null & undefined
是所有类型的子类型
void类型不能赋值给 number
let u: undefined = undefined; let n: null = null; let num: number = undefined; let u: undefined; let num: number = u; 复制代码
└void 类型
一般表示函数没有返回值。用在变量上没有什么卵用。
function warnUser(): void { console.log("This is my warning message"); } let a: void = undefined let a: void = 'undefined' // 报错,这是字符串 复制代码
跟它相似的类型还有 undefined
和 null
在不开启严格空检查的情况下 --strictNullChecks
,他们可以赋值给所有已经定义过***其他类型***的变量。
也就是说他们是所有类型的子类型
let a: undefined = undefined let a: null = null 复制代码
└数字 number
TypeScript里的所有数字都是浮点数。 这些浮点数的类型是 number。支持十进制和十六进制字面量二进制和八进制字面量。
let decLiteral: number = 6; let hexLiteral: number = 0xf00d; // ES6 中的二进制表示法 let binaryLiteral: number = 0b1010; // ES6 中的八进制表示法 let octalLiteral: number = 0o744; let notANumber: number = NaN; let infinityNumber: number = Infinity; 复制代码
└字符串 string
单双引 ''
""
,模板字符的都被视为字符串
let str:string = '' 复制代码
:star:️数组类型
有多种声明数组的方式
-
最简单的方法是使用
类型 + []
来表示数组:
const arr: number[] = [1,2,3] const arr2: string[] = ['1','2'] 复制代码
- 数组泛型定义方式
const arr2: Array<number> = [1,2,3,3] const arr2: Array<string> = [1,2,3,3] 复制代码
- 接口表示数组
interface NumArr { [index: number]: number; } let numArr: NumArr = [1,2,3]; 复制代码
- any 类型数组
let list:any[] = [1,"z",{}] 复制代码
- 元组类型声明
// 表示一个确定数组长度和类型的写法 const arr:[string,number] = ['2',3] 复制代码
- 类数组
就是伪数组的定义
官方已给了各自的定义接口 Arguments
, NodeList
, HTMLCollection
function sum() { let args: IArguments = arguments; } 复制代码
枚举 enum
js中没有这类型,仿照强类型语言来的。值只能为数字,不定义默认值得情况为从0开始。
enum Color {Red, Green, Blue} let c: Color = Color.Green; // c = 1 enum Number {one = 10, two} let c: Number = Number.two; // c = 11 复制代码
:star:️any 类型(任意值)
指代所有的类型
let a: any = '123' let a = 123; // 不声明默认 any 复制代码
never
表示永远不存在的值,一般会用来写抛出异常或推断为返回值为never的函数。(比如return一个其他的never类型)
function error(message: string): never { throw new Error(message); } error('a') 复制代码
object 类型
非简单类型 也就是除number,string,boolean,symbol,null或undefined之外的类型。
function create(o: object | null): void{ console.log(o); }; create({ prop: 0 }); // OK create(null); // OK create([]); // OK create('a'); // error 复制代码
:star:️interface 接口
在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。
对对象的描述
接口一般首字母大写。
赋值的时候,变量必须和接口保持一致。
interface Person { name: string; age: number; } let tom: Person = { name: 'Tom', age: 25 }; 复制代码
└可选属性
不想完全匹配某个接口,通过 ?
表示这个属性是可选的
仍然不允许添加未定义的属性
interface Person { name: string; age?: number; } let tom: Person = { name: 'Tom' }; 复制代码
└任意属性
让接口允许添加任意的属性值
[propName: string]: any;
interface Person { name: string; age?: number; [propName: string]: any; } let tom: Person = { name: 'Tom', gender: 'male' }; 复制代码
一旦定义了任意属性, 那么确定属性和 ?
可选属性都必须是任意属性的 子集
interface Person { name: string; age?: number; [propName: string]: string; } let p:Person = { name: 'zzc', age: 12, // error , 定义了 propName 必须将值设定为 string 类型 gender: 'male' , } 复制代码
└只读属性 readonly
相当于是常量了,初次赋值后不能重新赋值
做为变量使用的话用 const
,若做为属性则使用 readonly
。
interface demo { readonly a: string; // readonly定以后不能改值 b: number } let obj: demo = { a: 'ss', b: 1 } obj.a = 'aa' // error obj.b = 2 // success 复制代码
只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
interface Person { readonly id: number; } const tom: Person = {} // error tom.id = 1 // error, 复制代码
会报两次错,第一个是因为指定了 id,但没有给 id 赋值
第二个错是给只读属性id赋值了
└ReadonlyArray
通过 ReadonlyArray
定义的数组,再也无法改变了。
let a: number[] = [1, 2, 3, 4]; let ro: ReadonlyArray<number> = [1,2,3]; a[0] = 10 // success ro[0] = 12; // error! ro.push(5); // error! ro.length = 100; // error! a = ro; // 注意! 将readonly的值赋值给一个可变得数组也是不行的。 a = ro as Array<any> // 但是可以用断言重写 复制代码
:star:️函数类型
常见的函数声明方式有: 函数声明 & 函数表达式
用 ts 定义函数要考虑它的输入和输出
- 函数声明方式定义
function sum(a:number,b:number):number{ return a+b } // 形参和实参数量要一致 sum(1) // error sum(1,2) //3 sum(1,2,3) // error 复制代码
- 函数表达式定义
// 方式 1 let sum = function(a:number,b:number):number { return a + b; } // 方式二 let sum: (x: number, y: number) => number = function (x: number, y: number): number { return x + y; }; 复制代码
方式一中只对等号右侧的匿名函数定义了类型,左边是ts通过类型推论定义出来的
方式二才是给 sum 定义类型,**其中的 =>
不是 es6的 =>
** ,它用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
因为和 es6箭头函数可能造成混淆,最好用方式一;
└可选参数
通过 ?
给函数定义可选参数
可选参数后面不允许再出现必须参数了
如果给参数添加了默认值,ts 会自动识别为可选,且不受上一条规则的限制。
function sum(a:number,b?:number){} function sum(a?:number,b:number){} // error function sum(a:number = 1,b:number){} // 默认值,识别为可选,且不报错 复制代码
└...rest
使用…rest获取剩余参数,使用数组类型去定义它
剩余参数必须是函数的最后一个参数
function (a, ...items:any[]){} function (...items:any[], a){} // error 复制代码
└函数的重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
可以重复定义一个函数的类型
function say(somthing:string):string; function say(somthing:number):string; // 以上是函数定义 // 以下是函数实现 function say(somthing:string|number):string|number { return somthing } 复制代码
注意,TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。
:star:️类型断言
类型断言(Type Assertion)可以用来手动指定一个值的类型。
断定这个变量的类型是啥
类型断言不是类型转换
两种写法
<类型>值
or 值 as 类型
如果在 tsx 语法中使用,必须用 as
- 例子
联合类型可以指定一个变量为多种类型,此变量只能访问类型们的共有方法。
但一些情况下我们必须使用某一类型的方法或属性时,就可以用断言
function say(something:number|string):void{ alert(something.length) // 联合类型,报错 } // ==> 使用断言, 在变量前加上 <类型> function say(something:number|string):void{ alert( (<string>something).length ) // success } 复制代码
断言成一个联合类型中不存在的类型是不允许的
function say(something:number|string):void{ alert(<boolean>something.length) // 联合类型没有 boolean ,error } 复制代码
:star:️declare 声明
第三方库会暴露出一个变量,让我们在项目中直接使用。
但是 ts 编译时不知道这是啥,编译无法通过。
此时我们就要用 declare var
声明语句来定义他的类型
// 比如 jquery $('div') // ERROR: Cannot find name 'jQuery'. // ==> 使用 declare var 第三方库变量: (参数: string) => 返回类型 declare var $: (selector: string) => any; $('#foo'); // success 复制代码
declare var
并不是真正的声明一个变量,编译完会删除,仅仅是定义类型。
└声明文件
通常我们会把声明语句放到一个单独的文件( *.d.ts
)中,这就是声明文件
声明文件必需以 .d.ts
为后缀
假如仍然无法解析,那么可以检查下 tsconfig.json
中的 files
、 include
和 exclude
配置,确保其包含了 jQuery.d.ts
文件。
// src/jQuery.d.ts declare var jQuery: (selector: string) => any; 复制代码
这只是非模块化项目中使用的例子
└第三方声明文件
当然,jQuery 的声明文件不需要我们定义了,社区已经帮我们定义好了: jQuery in DefinitelyTyped 。
我们可以直接下载下来使用,但是更推荐的是使用 @types
统一管理第三方库的声明文件。
@types
的使用方式很简单,直接用 npm 安装对应的声明模块即可,以 jQuery 举例:
npm i @types/jquery -D 复制代码
可以在这个页面搜索你需要的声明文件。
└自定义声明文件
声明文件有以下方法
-
全局变量:通过
<script>
标签引入第三方库,注入全局变量 -
npm 包:通过
import foo from 'foo'
导入,符合 ES6 模块规范 -
UMD 库:既可以通过
<script>
标签引入,又可以通过import
导入 -
模块插件:通过
import
导入后,可以改变另一个模块的结构 -
直接扩展全局变量:通过
<script>
标签引入后,改变一个全局变量的结构。比如为String.prototype
新增了一个方法 -
通过导入扩展全局变量:通过
import
导入后,可以改变一个全局变量的结构
这里只记录 npm 导入的方法, 其他请看书写声明文件
在给一个第三方库写声明文件之前,先查看这个库有没有声明文件。一般来说,npm 包的声明文件可能存在于两个地方:
-
跟 npm 包绑在一起,
package.json
中有type
字段,或者有index.d.ts
声明文件。一般常用的包都有了,自己要发布 npm 包的时候最好也绑定在一起。 -
发布到了@types]( microsoft.github.io/TypeSearch/
) 里,一般这种情况是作者没写,其他人写了发上去的。
npm install @types/foo --save-dev
直接通过安装。
如果都没有,才自己写。
声明文件存放的位置是有约束的,一般在两个位置。
-
在
node_modules
创建第三方库的声明文件,但这种一般不采纳。一般node_modules
不会随我们的应用发布到服务器|git上。 -
创建一个
types
目录来写,要配合tsconfig.json
来使用。
# 项目结构 ├── README.md ├── src | └── index.ts ├── types | └── foo | └── index.d.ts └── tsconfig.json 复制代码
- 配置
{ "compilerOptions": { "module": "commonjs", "baseUrl": "./", "paths": { "*" : ["types/*"] } } } 复制代码
不管采用了以上两种方式中的哪一种,我都 强烈建议
大家将书写好的声明文件(通过给原作者发 pr,或者直接提交到 @types
里)发布到开源社区中,享受了这么多社区的优秀的资源,就应该在力所能及的时候给出一些回馈。只有所有人都参与进来,才能让 ts 社区更加繁荣。
- export
npm 包写的声明文件 declare
不会声明一个全局变量,只有导出的时候才会应用类型声明。
export const name: string; // 简单类型 export function getName(): string; // 函数 export class Animal { // class 声明 constructor(name: string); sayHi(): string; } export interface Options { // 接口 data: any; } // ===> 对应使用到项目中 import { name, getName, Animal, Directions, Options } from 'foo'; let myName = getName(); let cat = new Animal('Tom'); let options: Options = { data: { name: 'foo' } } 复制代码
-
混用
declare
export
通过 declare 定义多个变量,一次性导出
declare const name: string; declare function getName(): string; declare class Animal { constructor(name: string); sayHi(): string; } export { name, getName, Animal, } 复制代码
- 导出默认值
只有 function
、 class
和 interface
可以直接默认导出,其他的变量需要先定义出来,再默认导出
针对默认导出,一般会把导出语句烦恼歌在声明文件的最前面。
export default function foo(): string; export default interface Options { data: any } export default class Person { constructor(name: string); sayHi(): string; } declare const str:string; export default str; 复制代码
-
export namespace
namespace
本来是 TS 的模块化方案,随着 es6越来越屌基本已经不在 ts 中使用了。
但是声明文件中还是很常用的,表示变量是一个 包含了子属性的对象 类型。
像是 lodash
,它是个对象,但提供了很多子属性方法如 lodash.debunce
如果对象拥有深层的层级,则需要用嵌套的 namespace
来声明深层的属性的类型:
总的来说,用来导出一个拥有子属性的对象。
export namespace obj { const name: string; function fn(a:string,b?:nnumber):void; class Event { say(str:string):void }; // 如果还有包含子属性的对象,就嵌套 namespace sonObj { const foo: string; } } 复制代码
└声明合并
当一个变量,既是函数又是对象。可以组合多个语句声明。
export function objAndFn(foo:string):any; export namespace objAndFn { function fn(boo:number):void; const name:string; } 复制代码
└针对 commonjs
规范
用以下方式来导出:
// 整体导出 module.exports = foo; // 单个导出 exports.bar = bar; 复制代码
在 ts 中,针对这种导出,有多种方式可以导入,第一种方式是 const ... = require
:
// 整体导入 const foo = require('foo'); // 单个导入 const bar = require('foo').bar; 复制代码
第二种方式是 import ... from
,注意针对整体导出,需要使用 import * as
来导入:
// 整体导入 import * as foo from 'foo'; // 单个导入 import { bar } from 'foo'; 复制代码
第三种方式是 import ... require
,这也是 ts 官方推荐的方式:
// 整体导入 import foo = require('foo'); // 单个导入 import bar = require('foo').bar; 复制代码
对于 commonjs
规范的库,需要使用 export = 变量
的语法写声明文件
准确地讲, export =
不仅可以用在声明文件中,也可以用在普通的 ts 文件中。实际上, import ... require
和 export =
都是 ts 为了兼容 AMD 规范和 commonjs 规范而创立的新语法
export = foo; declare function foo():string; declare namespace foo { const bar: nnumber; } 复制代码
:star:️内置对象
TS定义了 js 中内置对象的类型,在 TypeScript 核心库的定义文件 中。
包括 ECMAscript、DOM、Bom 等
这些内置对象的类型在 .ts
中都可以直接使用
let b: Boolean = new Boolean(1); let e: Error = new Error('Error occurred'); let d: Date = new Date(); let r: RegExp = /[a-z]/; let body: HTMLElement = document.body; let allDiv: NodeList = document.querySelectorAll('div'); document.addEventListener('click', function(e: MouseEvent) { // Do something }); 复制代码
还会在该内置对象中定位错误
Math.pow(10, '2'); // error 必须是两个 number 型 document.addEventListener('click', function(e) { console.log(e.targetCurrent); // error, MouseEvent 类型不存在 targetCurrent属性 }); 复制代码
内置对象不包含 Node ,如果要使用
npm install @types/node --save-dev 复制代码
类
这章是介绍面向对象编程
class Greeter { greeting: string; constructor(message: string) { this.greeting = message; console.log(this.greeting); // world } greet() { return "Hello, " + this.greeting; } } let greeter = new Greeter("world"); 复制代码
继承
基本继承 作为基类的类一般被叫做超类,继承的类叫做派生类
class Car { name: string = '大众'; by() { console.log(this.name); } } class Baoma extends Car { name: string = '宝马' } let bm = new Baoma() bm.by() 复制代码
在子类 constructor
构造函数中***必须调用一下super***,它会执行基类的构造函数
在子类 constructor
构造函数调用this之前必须先调用super
class FClass { name: string = '超类' constructor(name: string) { this.name = name; } setAge(age:number) { console.log(`${this.name} is ${age}`); } } class SClass extends FClass { constructor(name:string) { super(name) } } let f = new SClass('zzc') f.setAge(20) 复制代码
公共,私有与受保护的修饰符
public
可以被除自己之外的所以子类访问到
ts中所有成员默认为 public
当一个成员被标记成 private
时,无法被外部访问
如果类的 constructor
声明成了 private
那就没办法 new
和继承了。 protected
受保护的,跟 private
基本一样,但它在子类中可以访问;
class FClass { name: string = '超类' private constructor(name: string) { this.name = name; } setAge(age:number) { console.log(`${this.name} is ${age}`); } } let f = new FClass() // error class Son extends FClass {} // error 复制代码
protected 受保护的例子
class F { protected name: string; constructor(name: string) { this.name = name; } setAge(age:number) { console.log(`${this.name} is ${age}`); } } class Son extends F { constructor() { super('son') } getName() { super.name // 可以在子类访问 } } let f = new F('super class') let s = new Son() console.log(s.name); // 不能在外部访问 console.log(s.getName()); // 但可以通过子类的方法return出来获取到 复制代码
在类中使用readonly
在类中或者 constructor
都还可以更改 readonly
的值,但在外部就无法更改了。
class F { readonly a:number = 8 constructor(age:number) { this.a = age } } let f = new F(9) f.a = 10 // error 无法在外部更改 复制代码
- 参数属性
在 constructor
用一句话定义并赋值一个属性
只要在参数前面加了 访问限定符
就可以直接给一个属性直接赋值 readonly
protected
public
private
static
是私有的,所以不能加。
class F { readonly a:number = 8 constructor(readonly b:number) { b = 10 } } let f = new F(9) console.log(f); // {a,b} 复制代码
存取器 getter/setters
当一个属性只有get方法的时候,它就是只读的。 这也是一种外部改变静态属性的方法
// 当a = 'a' 时,内部的_a才会等于赋的值,否则报错。 class F { private _a:string; get a():string { return this._a } set a(newA:string) { if(newA === 'a') { this._a = newA } else { this._a = 'error' } } } let f = new F() f.a = 'b' console.log(f); 复制代码
静态属性 static
它只挂在class本身,而不是通过new实例化后出来的对象
所以你可以通过 类.static属性
来调用,但不能用 this
class F { static num: number; changeStatic() { F.num = 19; } constructor () { this.changeStatic() console.log(F.num); } } let f = new F(); 复制代码
抽象类 & abstract
abstract
用来定义抽象类 和 在抽象类中定义抽象方法的
抽象类就是派生类的一个模板类,一般不会把它实例化,只是给子类继承用的。
abstract class Animal { // 抽象一个Animal类 abstract makeSound(): void; // 抽象一个方法,必须在子类实现它 move(): void { console.log('roaming the earch...'); } constructor () { } } class Son extends Animal { constructor() { super() } makeSound() { // 必须实现抽象类中的方法 return false } haha() { console.log('error'); } } let s:Animal // 可以指定抽象类为一个类型 s.haha() // 如果上面的声明了,那么调用抽象类中不存在的haha方法是不允许 s = new Animal() // 不可以new 抽象类 s = new Son() // 正确 s.makeSound() // 正确 复制代码
:star:类型推论
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。
let myFavoriteNumber = 'seven'; myFavoriteNumber = 7; // error // 等价于 ==> let myFavoriteNumber: string = 'seven'; myFavoriteNumber = 7; 复制代码
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
let myFavoriteNumber; myFavoriteNumber = 'seven'; myFavoriteNumber = 7; 复制代码
:star:️联合类型
表示变量可以是多种类型其中的一种
通过 |
分隔
let numOrStr : string | number; numOrStr = 7; numOrStr = '7'; numOrStr = true; // false 复制代码
当调用联合类型的方法时,只能调用俩类型中共有的方法。
let numOrStr : string | number; numOrStr.length // 报错 length 不是 number 的方法 numOrStr.toString() // 可以 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
推荐系统
[奥地利] Dietmar Jannach、Markus Zanker、Alexander Felfernig、Gerhard Friedrich / 蒋 凡 / 人民邮电出版社 / 2013-6-25 / 59.00元
编辑推荐: 通过对本书的学习,读者不仅可以全面系统地了解该领域的基础原理,还能试验如何搭建一套真正的推荐系统。 —— 百度主任架构师、百度技术委员会主席 廖若雪 本书比较全面地介绍了推荐系统涉及的相关知识点,很适合对于推荐系统感兴趣的相关人员作为入门教程,目前能够系统全面介绍相关技术的中文书籍还显得匮乏,相信这本译著对于缓解这种情况大有裨益。 ——新浪微博数据挖掘技术专家 ......一起来看看 《推荐系统》 这本书的介绍吧!