TypeScript是JavaScript类型的超集,它可以编译成纯JavaScript。
TypeScript可以在任何浏览器、任何计算机和任何操作系统上运行,并且是开源的。
简单的说
Type + JavaScript = TypeScript
倔强的你就是不想用
你需要在 HTML 里大量嵌入 JavaScript 代码,而非 HTML 和 JavaScript 分离
项目中大量依赖了第三方 JavaScript 类库,并且这些类库没有 .d.ts 文件
你是 “微软雅黑”
var/let/const 变量名: 类型 = 值;
let num: number = 18;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
let name: string = 'qq';
let word: string = `my name is ${word}`;
let isDone: boolean = true;
let n: null = null;
let u: undefined = undefined;
空类型,表示没有类型,比如无返回值函数的返回值类型
function foo(): void {
}
let unusable: void = undefined;
任意类型,表示未知类型,比如动态内容(用户输入、或第三方类库)或不知道类型的东西(混合类型数组),可以声明any类型绕过类型检查
let str: any = 1;
str = '1';
不要让你的代码成为AnyScript
绝不存在的值的类型,如永远不会返回的函数(必定抛异常的,或函数体有死循环的)的返回值类型
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {
}
}
只有这些怎么够呢?
let nums: number[] = [1, 2, 3];
let strs: string[] = ['你', '好', '呀' , '!'];
let baz: Array<any> = ['你', '好', 6 , true];
元组,表示一组固定数量的元素(不要求元素类型相同),如二元组,三元组
let status: [string, string, number] = ["DONE", "已结束", 4];
enum OrderStatus {
UNPAID = 0,
UNUSED,
USING,
INVALID,
DONE
}
let state: number = OrderStatus.DONE;
双向索引
let stateStr: string = OrderStatus[OrderStatus['DONE']]; // DONE
可以通过类型断言告知TypeScript编译器某个值的确切类型,类似于其它语言里的强制类型转换,区别在于类型断言只是编译时的,不像类型转换一样具有运行时影响
let someValue: any = "this is a string";
// <type>
let length1: number = (<string>someValue).length;
// as type
let length2: number = (someValue as string).length;
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// index.ts(2,1):
// error TS2322:
// Type 'number' is not assignable to type 'string'.
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;
表达能力还是不够
TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。
不喜欢看官方的描述?
interface就是用来描述对象的属性和方法,和C语言中的struct更像一些。
let fe1: { name: string, age: number } = {
name: '奥利安奇',
age: 18
};
let fe2: { name: string, age: number } = {
name: 'Xeon',
age: 18
};
// other fe...
interface IFe {
name: string;
age: number;
}
let fe1: IFe = {
name: '奥利安奇',
age: 18
};
let fe2: IFe = {
name: 'Xeon',
age: 18
};
// other fe...
interface IPatient {
name: string;
phone: string;
age: number;
idCode?: string
}
interface IPatient {
readonly id: number;
name: string;
phone: string;
age: number;
idCode?: string
}
有些场景下无法确定属性名称
interface IPatient {
name: string;
phone: string;
idCode?: string;
[prop: string]: string;
}
let patient: IPatient;
patient['sex'] = '男';
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
interface Base64 {
encode(input: string): string;
decode(input: string): string;
}
let base64: Base64;
base64.encode('1234');
base64.decode('sxdwwq');
interface GetStrLength {
(str: string): number;
}
let foo: GetStrLength = (s: string) => s.length;
interface Nums {
[index: number]: number;
}
let arr: Nums = [1, 2];
function add(x: number, y: number): number {
return x + y;
}
let add: (x: number, y: number) => number =
function (x: number, y: number): number { return x + y; };
JavaScript里参数默认都是可选的(不传的默认undefined),而TypeScript认为每个参数都是必填的,除非显式声明可选参数
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob");
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams");
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
buildName('Will', 123); //error 类型“123”的参数不能赋给类型“string”的参数
带默认值的参数不需要放在必须参数的后面,但必须明确的传入 undefined值来获得默认值
function buildName(firstName = "Will", lastName: string) {
return firstName + " " + lastName;
}
buildName(undefined, "Smith");
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
$('a')
$(document.querySelector('a'))
$([])
$(function () { })
Minimal Class
class Message {
static version = '1.0.0';
constructor() {
this.messages = [];
}
get hasReads() {
return this.messages.filter(item => !item.read)
}
add(msg) {
this.messages.push({
content: msg,
read: false
});
}
clear() {
this.messages = [];
}
}
class Animal {
private name: string;
constructor(theName: string) {
this.name = theName;
}
protected foo(): void {
console.log(this.name);
};
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
注意,这些访问控制都只是编译时的限制,运行时并不做强检查。符合TypeScript的设计原则:
不给编译产物增加运行时开销
var Animal = /** @class */ (function () {
function Animal(theName) {
this.name = theName;
}
Animal.prototype.foo = function () {
console.log(this.name);
};
Animal.prototype.move = function (distanceInMeters) {
console.log(this.name + " moved " + distanceInMeters + "m.");
};
return Animal;
}());
but!!!!
class RGBColor {
#hex
constructor(r, g, b) {
#hex = r * 0x10000 + g * 0x100 + b
}
toString() {
return `rgb(${this.red}, ${this.green}, ${this.blue})`
}
get red() { return #hex >> 16 }
get green() { return (#hex >> 8) & 0xff }
get blue() { return #hex & 0xff }
static equals(c1, c2) {
return c1.#hex === c2.#hex
}
}
class Animal {
// 声明和赋值合并
constructor(public readonly name: string) { }
}
let a: Animal = new Animal('Tom');
a.name = 'jerry';
// Cannot assign to 'name' because it is a read-only property.ts(2540)
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log('roaming the earch...');
}
}
接口只能定义抽象方法
等等…我还没想好…☺️
不要问我了!我真不知道😭
import axios from 'axios';
axios.get('/user/1').then(response => {
let user = response.data; // user长啥样 🤔🤔
});
axios.get('/patients').then(response => {
let patients = response.data; // patients又长啥样🤔🤔
});
function createArray<T>(length: number, value: T): T[] {
let result = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
interface GenericIdentityFn {
<T>(arg: T): T;
}
interface GenericIdentity<T> {
id(arg: T): T;
idArray(...args: T[]): T[];
}
class Component<IProp, IState>{
constructor(
public readonly prop: IProp,
state: IState
) { }
}
interface AppProp {
name: string;
}
interface AppState {
count: number;
}
const App =
new Component<AppProp, AppState>({ name: 'MyAPP' }, { count: 1 });
class Component<IProp extends { parentName: string }, IState> {
constructor(
public readonly prop: IProp,
state: IState
) { }
}
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
TypeScript 也支持JSX,只需 2 步,即可使用 TypeScript 写 JSX:
class App extends React.Component {
render() {
return (<div>App</div> );
}
}
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
}
函数式组件
class组件
vue-class-component、 vue-property-decorator、 vuex-class、 TodoMvc-vue
import { Vue, Component, Watch } from "vue-property-decorator";
import { State } from "vuex-class";
import TodoHeader from "@/components/todo-header.vue";
import TodoMain from "@/components/todo-main.vue";
import TodoFooter from "@/components/todo-footer.vue";
import { saveTodos } from "@/utils/store.ts";
import { Todo } from "@/types/todo";
@Component({
components: {
TodoHeader,
TodoMain,
TodoFooter
}
})
export default class App extends Vue {
@State(state => state.todo.todoList)
todoList!: Todo[];
@Watch("todoList", { deep: true, immediate: true })
todoListChange(todos: Todo[]) {
saveTodos(todos);
}
}
the Class API proposal is being dropped
所以没有折腾精神,追求稳定,还是等Vue3吧
用于构建高效且可伸缩的服务端应用程序的渐进式 Node.js 框架。
告诉typescript如何编译ts文件,比如前面提到的--jsx
选项,编译后的js版本(target
等等)
如果一个目录下存在一个tsconfig.json
文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json
文件中指定了用来编译这个项目的根文件和编译选项。
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist"
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json"]
},
module: {
rules: [
{ test: /\.tsx?$/, loader: "ts-loader" },
]
}
};
var gulp = require("gulp");
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");
gulp.task("default", function () {
return tsProject.src()
.pipe(tsProject())
.js.pipe(gulp.dest("dist"));
});
并不是所有的文件都是使用typescript编写的,当使用这些由JavaScript编写的第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
`@types/react`、 `@types/react-dom` 、`types/react-redux` ...
仓库地址:[DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/)
declare let jQuery: (selector: string) => any;
编写声明文件也是学习typescript的一个很好的入门途径
打游戏时拿命在C的