npm install -g typescript
tsc -v
tsc --init
tsc xx.ts 编译 xx.js
node xx.js
npm install ts-node -g
ts-node xx.ts
let isDone: boolean = false;
let decLiteral: number = 6;
let bigLiteral: bigint = 100n;
let name: string = "bob";
let list: number[] = [1, 2, 3];
也可以写复杂的数组类型
interface List {
name: string;
}
const list: List[] = [{ name: "xr" }];
// 联合类型的数组
const list: (string | number)[] = [1, "2"];
let list: Array<number> = [1, 2, 3];
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
let x: [string, number] = ["xr", 18];
enum 类型是对 JavaScript 标准数据类型的一个补充。
enum Days {
Sun=3,
Mon,
Tue,
Wed
}
console.log(Days.Sun); // 默认为 0 如果写值 则从 值上面3开始
反向映射
console.log(Days[4]); // Mon
const enum Enum {
A
}
外部枚举
外部枚举用来描述已经存在的枚举类型的形状。
declare enum Enum {
A
}
尽量使用 Unknown
替代 any
let notSure: unknown = 4;
notSure = "maybe a string instead";
let notSure: any = 4;
notSure = "maybe a string instead";
通常用在函数没有返回值情况
function warnUser(): void {
console.log("This is my warning message");
}
let u: undefined = undefined;
let n: null = null;
never 类型表示的是那些永不存在的值的类型。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {}
}
object 表示非原始类型,也就是除 number,string,boolean,bigint,symbol,null 或 undefined 之外的类型。
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
interface LabeledValue {
label: string;
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label);
}
let myObj = { label: "Size 101 Object" };
printLabel(myObj);
有些是只在某些条件下存在,或者根本不存在
interface LabeledValue {
label: string;
value?: string;
}
function printLabel(labeledObj: LabeledValue) {}
let myObj = { label: "Size 101 Object" };
let myObj2 = { label: "Size 101 Object", value: "value" };
interface LabeledValue {
readonly label: string;
}
function printLabel(labeledObj: LabeledValue) {
// 无法分配到 "label" ,因为它是只读属性。ts(2540)
labeledObj.label = "new label";
}
在接口中定义了某个属性 使用时超过这些属性直接写字面量方式会报错,写在变量中正常
interface LabeledValue {
label: string;
}
function printLabel(labeledObj: LabeledValue) {}
// 这种写法可以
let myObj = { label: "Size 101 Object" };
printLabel(myObj);
// 这种写法报错
// 类型“{ label: string; value: string; }”的参数不能赋给类型“LabeledValue”的参数。对象文字可以只指定已知属性,并且“value”不在类型“LabeledValue”中。ts(2345)
printLabel({ label: "Size 101 Object", value: "value " });
接口改写
propName 可以任意变量
[propName: string] 表示以后添加的属性是 string 类型,属性值是 any 类型
interface LabeledValue {
label: string;
[propName: string]: any;
}
interface Func {
(name: string, age: number): number;
}
var func: Func = function (name: string, age: number): number {
return age;
};
interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class Clock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = function(start: number) {} as Counter;
counter.interval = 123;
counter.reset = function() {};
return counter;
}
interface St extends Per {}
继承多个写法
interface St extends Per, Stu {}
interface Per {
name: string;
}
interface Per {
age: number;
}
const per: Per = { name: "xr", age: 0 };
type strType = string | number | boolean;
let strT: strType = 10;
strT = "11";
type user = {
name: string,
};
type setuser = (name: string) => void;
type strType3 = "男" | "女";
function getSex(sex: strType3) {
return sex;
}
getSex("男");
interface Type {
name: string;
}
interface Type2 {
age: number;
}
type strType2 = Type | Type2;
// let strT2: strType2 = { name: 'zs', age: 33 }
let strT2: strType2 = { name: "zs" };
// let strT2: strType2 = { age: 33 };
type User = {
name: string,
};
type Per = User & {
age: number,
};
const per: Per = { name: "xr", age: 20 };
let type: string | number = 1;
type = "1";
interface Bird {
fly();
layEggs();
}
interface Fish {
swim();
layEggs();
}
declare function getSmallPet(): Fish | Bird;
let pet = getSmallPet();
pet.layEggs();
// 类型“Fish | Bird”上不存在属性“swim”。类型“Bird”上不存在属性“swim”。
pet.swim();
(pet as Fish).swim();
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
if (isFish(pet)) {
pet.swim();
}
else {
pet.fly();
}
function move(pet: Fish | Bird) {
if ("swim" in pet) {
return pet.swim();
}
return pet.fly();
}
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
interface ErrorHandling {
success: boolean;
error?: { message: string };
}
interface ArtworksData {
artworks: { title: string }[];
}
interface ArtistsData {
artists: { name: string }[];
}
// 这些接口被组合后拥有一致的错误处理,和它们自己的数据
type ArtworksResponse = ArtworksData & ErrorHandling;
type ArtistsResponse = ArtistsData & ErrorHandling;
const handleArtistsResponse = (response: ArtistsResponse) => {
if (response.error) {
console.error(response.error.message);
return;
}
console.log(response.artists);
};
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function (x: number, y: number): number {
return x + y;
};
let myAdd: (x: number, y: number) => number = function (
x: number,
y: number
): number {
return x + y;
};
function buildName(firstName: string, lastName?: string) {
if (lastName) return firstName + " " + lastName;
else return firstName;
}
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
class Demo {
title = "默认值";
constructor() {}
say() {
console.log(this.title);
}
}
const demo = new Demo();
console.log(demo.title);
class Demo {
constructor(public title: string) {}
}
class De extends Demo {}
const demo = new De("自定义");
console.log(demo.title);
public 默认值在类内,类外都可以访问
private 只能在类内部访问
protected 可以在类内部访问,也可以在继承中访问
class Demo {
public title = "默认值";
constructor(title: string) {
this.title = title;
}
}
const demo = new Demo("自定义");
console.log(demo.title);
属性的简写
class Demo {
constructor(public title: string) {}
}
const demo = new Demo("自定义");
console.log(demo.title);
class Demo {
constructor(
public title: string,
private age: number,
protected sex: string
) {}
}
const demo = new Demo("自定义", 20, "男");
console.log(demo.title);
属性“age”为私有属性,只能在类“Demo”中访问。
console.log(demo.age);
属性“sex”受保护,只能在类“Demo”及其子类中访问。
console.log(demo.sex);
class De extends Demo {
print() {
// 属性“age”为私有属性,只能在类“Demo”中访问。
console.log(this.age)
console.log(this.sex, this.title);
}
}
你可以使用 readonly 关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
class Demo {
public readonly title = "默认值";
}
const demo = new Demo();
console.log(demo.title);
// 无法分配到 "title" ,因为它是只读属性。ts(2540)
demo.title = "出错了";
class Person {
constructor(private _name: string) {}
get name() {
return this._name;
}
set name(val: string) {
this._name = val;
}
}
const per = new Person("xr");
console.log(per.name); // xr
per.name = "zs";
console.log(per.name); // zs
静态属性、方法只能类调用
静态方法中 this
指向类本身
class Demo {
static type = 1;
static say() {
return this.type;
}
}
console.log(Demo.type);
class Person {
// 存取实例对象
private static instance: Person;
// 使外部 不可以 `new Person`
private constructor() {}
// 添加类方法返回实例对象
static getInstance() {
// 静态方法中 `this` 指向类本身
if (!this.instance) {
this.instance = new Person();
}
return this.instance;
}
}
const per = Person.getInstance();
const per2 = Person.getInstance();
console.log(per === per2); // true
抽象类做为其它派生类的基类使用。
abstract class Department {
constructor(public name: string) { }
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
constructor() {
super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
}
printMeeting(): void {
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports(): void {
console.log('Generating accounting reports...');
}
}
let department: Department; // 允许创建一个对抽象类型的引用
department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // 错误: 方法在声明的抽象类中不存在
function identity<T>(arg: T): T {
return arg;
}
使用
第一种是,传入所有的参数,包含类型参数
let output = identity < string > "myString"; // type of output will be 'string'
第二种方法更普遍。利用了类型推论
let output = identity("myString"); // type of output will be 'string'
interface Identity {
<T>(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: Identity = identity;
let myIdentity2: <T>(arg: T) => T = identity;
interface Identity<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: Identity<string> = identity;
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
interface Person {
name: string;
age: number;
gender: string;
}
class Teacher {
constructor(public info: Person) {}
getInfo<T extends keyof Person>(key: T): Person[T] {
return this.info[key];
}
}
const teacher = new Teacher({
name: "xr",
age: 20,
gender: "男",
});
console.log(teacher.getInfo("gender"));
Demo.ts
namespace Demo {
export interface IDemo {
name: string;
}
}
const demo: Demo.IDemo = {
name: "demo",
};
Demo 是全局变量可以直接使用
要使用 Demo 下的 IDemo 接口就必须导出
Demo.ts
export namespace Demo {
export interface IDemo{
name: string;
}
}
xx.vue
import { Demo } from "./ts/demo";
const person: Demo.IDemo = { name: "xr" };
不必要的命名空间
再次重申,不应该对模块使用命名空间,使用命名空间是为了提供逻辑分组和避免命名冲突。
demo.ts
export interface IDemo {
name: string;
}
xx.vue
import { IDemo } from "./ts/demo";
const person: IDemo = { name: "xr" };
xx.d.ts
declare module "url" {
export interface Url {
protocol?: string;
hostname?: string;
pathname?: string;
}
export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url;
}
declare module "path" {
export function normalize(p: string): string;
export function join(...paths: any[]): string;
export let sep: string;
}
///
import * as URL from "url";
let myUrl = URL.parse("http://www.typescriptlang.org");
declare module "hot-new-module";
简写模块里所有导出的类型将是 any。
import x, { y } from "hot-new-module";
x(y);