目录
一.静态类型
一旦声明不可改变。
同时,声明类型的变量会继承所声明数据类型的方法
如下:count继承了number的方法
number是基础类型
除此之外还有
①对象类型
const xiaoJieJie: {
name: string,
age: number
} = {
name: 'da',
age: 18
}
②数组类型
const xiaoJieJies: string[] = ['12', '23', '34']
//上面这个例子必须传字符串数组
③类类型
class Person { };
const dajiao: Person = new Person();
// dajiao必须是一个Person的实例
④函数类型
const jianXiaoXiao: () => string = ()=>{return ''}
// jianXiaoXiao必须是一个函数并且返回值是一个字符串
二.类型注解和类型推断
1.类型注解
这句代码声明count是一个number类型的数据。这就是类型注解
let count: number = 1;
2.类型推断
这里ts可以自动判断three的类型为number。
这就是类型推断,根据已有类型对未知类型进行推断。
!!类型注解工作原则,ts能够自己推断的变量就不需要写类型注解,如果不能推断的就需要写类型注解。
像上面这种无法推断的就需要写类型注解
这种也不需要写
3.函数参数和返回类型的注解
有时候由于编写时的错误,可能导致变量在运行过程中类型被改变。如上面这种,程序并不会报错,所以需要对返回值进行注解。
function getTotal(one: number, two: number): number {
return one + two ;
}
const total1 = getTotal(1, 2);
永远也执行不完的代码可用never注释
第一个是抛出异常,打印永远执行不到
第二个是一个无限循环函数
这两个都可以用never来注释
function add({one,two}:{one:number,two:number}){
return one+two;
}
const totle8 = add({one:1,two:2})
当参数是一个对象时,需要以上面的方式写注释
4.数组类型注解
普通数组类型注解
1.类型别名
像上面这种对象定义可能很多地方都要重复使用如果每次都重复写{name:string,age:number}会相当繁琐。
可以使用类型别名,用变量保存
也可以使用类来定义
5.元组的使用和类型约束(使用得少)
const arr : (number | string)[] = [1,'sdfa',545]
//arr的注解允许定义number和string但是不会严格控制它的顺序 [1,'sdfa',545]或者 ['sdfa',1,'fdsf']都不会报错
const xiaojiejie: [string, string, number] = ["dajiao", "teacher", 28];
//如果想要严格控制顺序和类型需要使用元组,就像上面这样,第一个和第二个必须是string,第三个必须是number
三.接口
定义一个简单的接口,:前面写一个?就代表这个参数是可选的
interface Girl {
name: string;
age: number;
face: number;
waistline ?: number;
}
const girl={
name:'xiaowang',
age:18,
face:'handsome',
ll:1
}
const logInform = (girl:Girl)=>{
console.log(girl);
}
1.用接口管理类
interface Girl {
name: string;
age: number;
face: string;
waistline ?: number;
[propname:string]:any;
// 有一些除上面的固定名字以外,我们可能还需要定义一些别的属性
// 但是不想每个都定义一遍可以使用[propname:string]:any;
// 它的意思就是属性名是字符串,内容可以是任意数据类型
say():string;
// 我们还可以指定一些函数,上面的say的意思是:有一个say()函数,它的返回值是string
}
class XiaoJieJie implements Girl{
name='xiaowang'
age=18
face='handsome'
say(){
return 'hello world'
}
}
2.接口的继承
interface Girl {
name: string;
age: number;
face: string;
waistline?: number;
[propname: string]: any;
// 有一些除上面的固定名字以外,我们可能还需要定义一些别的属性
// 但是不想每个都定义一遍可以使用[propname:string]:any;
// 它的意思就是属性名是字符串,内容可以是任意数据类型
say(): string;
// 我们还可以指定一些函数,上面的say的意思是:有一个say()函数,它的返回值是string
}
interface teacher extends Girl{
teach():string;
}
teacher 接口除了有Girl的所有约束外,还有自身的teach函数约束。
也就是说使用teacher不仅要满足Girl的所有约束还要满足teacher的所有约束
四.类
子类的实例,既可以访问子类的属性和方法也可以访问父类的属性和方法
class Boy{
sex='man'
age=18
}
class studen extends Boy{
study(){
return 'I am learning!!'
}
}
const xiaoming = new studen;
console.log(xiaoming.age);
console.log(xiaoming.study);
重写:在子类中定义与父类同名的属性或函数就叫重写。访问时会访问到子类的函数。也可以使用super在子类中调用父类的函数,处理成一个新的函数
class Boy{
sex='man'
age=18
say(){
return 'I am a boy'
}
}
class studen extends Boy{
say(){
return super.say()+'hahaha'
}
study(){
return 'I am learning!!'
}
}
调用结果
1.类的访问类型
1.public 公共的(在类的内部和外部都可以访问)如果不写访问类型默认是public
2.private (只能在类的内部访问)
3.protected(只能在类的内部使用,可以在继承中的类使用)
class Animal{
public age:number;
private say(){
return 'hou'
}//这个花括号内就是类的内部
protected food:string;
}
class cat extends Animal{
eat(){
this.food
}
}
const dog = new Animal();
console.log(dog.age);
console.log(dog.say());
访问私有属性会报错
访问protected
class Animal{
public age:number;
say(){
return 'hou'
}
protected food:string='apple';
}
class cat extends Animal{
eat(){
return this.food
}
}
const miao = new cat();
console.log(miao.eat());
2.类的构造函数
class Person {
public name:string;
constructor(name:string){
this.name = name;
}
}
const person = new Person('xiaowang')
console.log(person.name);
等同于(简写)
class Person {
constructor(public name:string){
this.name = name;
}
}
const person = new Person('xiaowang')
console.log(person.name);
1.子类的构造函数
class Person {
constructor(public name:string){
this.name = name;
}
}
class Teacher extends Person{
constructor(public age:number){
super('xiaownag');
// 这里必须使用super调用父组件的构造函数,并传递name参数
}
}
const teacher = new Teacher(18)
console.log(teacher);
3.类的Getter,Setter,Static
1.Getter
直接访问私有属性_age会报错,但是可以使用get暴露属性,可用于类的封装
class XiaoJieJie{
constructor(private _age:number){}
get age(){
return this._age;
}
}
const dajiao = new XiaoJieJie(18)
console.log(dajiao.age+5);
2.Setter
可以对类的私有属性进行操作
class XiaoJieJie{
constructor(private _age:number){}
get age(){
return this._age+5;
}
set age(age:number){
this._age = age+3
}
}
const dajiao = new XiaoJieJie(18)
console.log(dajiao.age);
3.Static
普通方法调用
class Girl {
sayLove() {
return 'i love you!';
}
}
const girl = new Girl();
console.log(girl.sayLove());
调用类中的方法需要new一个实例,通过实例进行方法的调用
有时候我们希望不用new一个实例就能调用方法,这时候可以对方法进行静态化
class Girl {
static sayLove() {
return 'i love you!';
}
}
console.log(Girl.sayLove());
4.抽象类和只读属性
1.只读属性
class Person{
constructor(public name:string){}
}
const person = new Person('xiaowang');
person.name='xiaohuang';
console.log(person.name);
实例被创建之后,还是可以修改属性。如果不希望属性在实例创建之后被修改,可以使用只读属性。
class Person {
public readonly _name: string;
constructor(name: string) {
this._name = name;
}
}
const person = new Person('xiaowang');
person._name = 'xiaohuang';
console.log(person._name);
这样就会报错
2.抽象类
用abstract 定义抽象类和抽象方法。
所有继承抽象类的类都要实现抽象类的抽象方法。
abstract class Girl1{
abstract skill();
// 定义一个抽象方法
}
class Waiter extends Girl1{
skill(){
console.log('喝水');
// 所有继承抽象类的类都要实现抽象类的抽象方法
}
}
class BaseTeacher extends Girl{
skill(){
console.log('按摩');
}
}
五.tsconfig.json配置文件
“removeComments”: true,配置项设置ts编译成js后是否移除注释。
调用tsc命令会走tsconfig.json配置文件,如果写tsc tsc Dome.ts配置文件不会生效
"include":["Dome.ts"],
选择性生成js文件,数组内的文件会生成js文件,不在数组内的同一目录下的其他文件不会生成js文件。
"exclude":["Dome.ts"],
相对应的有exclude,除了数组里的文件,其他的都生成js文件。
"files":["Dome.ts"],
files和include差不多
1.compilerOptions
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
允许注解类型any不用特意声明
// "strictNullChecks": true, /* Enable strict null checks. */
设置为false 允许null值出现
// "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. */
是否严格类型检查,如果开启则下面所有配置项为true不能配置。
// "strictNullChecks": true, /* Enable strict null checks. */
const person:string = null ;
outDir是编译好的js的目录
rootDir是入口目录就是,ts文件的目录
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
项目的目录结构一般是这样src放ts文件,build里放编译后的js文件。
// "sourceMap": true, /* Generates corresponding '.map' file. */
生成,文件和编译后的文件的一个对应关系,排查错误会用到。
// "noUnusedLocals": true, /* Report errors on unused locals. */
没有用到的变量会提示
// "noUnusedParameters": true, /* Report errors on unused parameters. */
没有用到的方法会提示
六.联合类型和类型守护(类型保护)
interface Waiter {
skill: boolean;
say: () => {}
}
interface Teacher {
skill: boolean;
teach: () => {}
}
// 不止一种的就叫;联合类型
function jj(animal: Waiter | Teacher) {
animal.say()
}
当一个变量有一个以上的类型就是联合类型。访问其中一个类型的方法时就会报错,这时候需要用到类型保护。
1.类型断言
interface Waiter {
name: boolean;
say: () => {}
}
interface Teacher {
skill: boolean;
teach: () => {}
}
// 不止一种的就叫;联合类型
function jj(animal: Waiter | Teacher) {
if(animal.name){
(animal as Waiter).say()
}else{
(animal as Teacher).teach()
}
}
function kk(animal: Waiter | Teacher) {
if('say' in animal){
(animal as Waiter).say();
}else{
(animal as Teacher).teach();
}
}
案例:
instanceof只能用在类上
七.Enum枚举类型
enum Status{
MASSAGE,
SPA,
DATA,
}
console.log(Status.MASSAGE);
console.log(Status.SPA);
console.log(Status.DATA);
enum Status{
MASSAGE = 1,
SPA,
DATA,
}
console.log(Status.MASSAGE);
console.log(Status.SPA);
console.log(Status.DATA);
如果第一个赋值为1,则从1开始
enum Status{
MASSAGE = 1,
SPA,
DATA,
}
console.log(Status.MASSAGE,Status[1]);
console.log(Status.SPA);
console.log(Status.DATA);
通过下标也可以访问值
八.泛型
1.在函数中使用泛型
在函数定义的时候<>里的名字可以随便起,然后使用的时候需要进行指定,就像下面这个例子。
function join<XiaoWang>(first: XiaoWang, second: XiaoWang) {
return `${first}${second}`;
}
let s = join<string>("xiaowang", ' is a handsome boy');
console.log(s);
这个例子中定义了一个XiaoWang的泛型,名字可以随便起。使用的时候指定了string,所以first和second参数都是string类型。可以理解泛型就是一个指定类型的变量。
1.泛型中数组的使用
// 泛型中数组的使用
function myFun<ANY>(params: ANY[]) {
return params;
}
myFun<string>(['123','456']);
等同于
// 泛型中数组的使用
function myFun<ANY>(params: Array<ANY>) {
return params;
}
myFun<string>(['123','456']);
定义多个泛型
function join<T,P>(first: T, second: P) {
return `${first}${second}`;
}
let s = join<string,Number>("xiaowang", 2);
console.log(s);
2.在类中使用泛型
一个简单的例子
class SelectGirl<T>{
constructor(private girls: T[]) { }
getGirl(index: number): T {
return this.girls[index];
}
}
const selectGirl = new SelectGirl<number>([1,8])
console.log(selectGirl.getGirl(1));
泛型的继承:
interface Girl {
name: string;
}
class SelectGirl<T extends Girl>{
constructor(private girls: T[]) { }
getGirl(index: number): string {
return this.girls[index].name;
}
}
const selectGirl = new SelectGirl([
{name:'xiaowang'},
{name:'xiaohuang'},
{name:'xiaoliu'}
])
console.log(selectGirl.getGirl(1));
泛型的约束,泛型只能是number或string
九.命名空间
page.ts
只暴露出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();
}
}
}
page.js
"use strict";
var Home;
(function (Home) {
var Header = /** @class */ (function () {
function Header() {
var elem = document.createElement('div');
elem.innerText = 'this is header';
document.body.appendChild(elem);
}
return Header;
}());
var Content = /** @class */ (function () {
function Content() {
var elem = document.createElement('div');
elem.innerText = 'this is Content';
document.body.appendChild(elem);
}
return Content;
}());
var Footer = /** @class */ (function () {
function Footer() {
var elem = document.createElement('div');
elem.innerText = 'this is Footer';
document.body.appendChild(elem);
}
return Footer;
}());
var Page = /** @class */ (function () {
function Page() {
new Header();
new Content();
new Footer();
}
return Page;
}());
Home.Page = Page;
})(Home || (Home = {}));
html
需要用命名空间的类名调用暴露出的类
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./build/page.js"></script>
<title>Document</title>
</head>
<body>
<script>
new Home.Page();
</script>
</body>
</html>
命名空间可以嵌套
namespace Components{
export namespace SubComponents{
export class Test{}
}
}
配置ts转js只生产一个文件
amd的语法无法直接被浏览器识别,需要引入一个插件require.js
十.TypeScript的import写法
compontens.ts
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
import { Header, Content , Footer} from "./components";
export default class Page{
constructor(){
new Header();
new Content();
new Footer();
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js"></script>
<script src="./build/page.js"></script>
<title>Document</title>
</head>
<body>
<script>
require(['page'],function(page){
new page.default();
})
</script>
</body>
</html>