TS的学习经历
最早接触TypeScript是16年,为了学习面向对象编程,我把手头上用prototype
实现的一个JS模块改用class
去实现,特意去下载了webstorm并启用了TS文件的自动编译功能。虽然在这过程中顺便学习到了一些类型相关的知识,但此时的我还没有感受到TS的强大以及它的复杂。不过在改写的过程中倒是觉得TS将Class对语法转译为ES5中原型链的操作挺神奇的,同时也对这两种写法的区别加深了印象。
下面是上述代码的一些稚嫩的片段:
ts
/// <reference path="jquery.d.ts" />
interface data{
song_name:string;
artist:string;
lrc_name:string;
spe_zh:string;
spe_en:string;
oth_src:string;
qiniu_src:string;
}
interface getData{
[index:number]:data;
}
interface songInfo{
idx:number;
song_name:string;
}
interface spePre{
timer : any;
spe_en:string;
moved:number;
}
interface bgImg{
timer:any;
inter:number;
}
interface theme{
type:string;
count:number;
}
var SIZE = 128;
var rang = SIZE;
class Music{
allSongData:getData;
currentSong:number=0;
list = $('#m-list');
listLi:any;
listBtn = $('#m-box h3');
lyricContainer = $('.lyc-container');
rateBar = $('#timeProgress .progress-bar');
rate = $('#timeProgress');
volBar = $('#vol .progress-bar');
vol = $('#vol .progress');
f_play = $('#f-play');
f_prev = $('#f-prev');
f_next = $('#f-next');
spe = $('.spe>img');
spePre:spePre={};
randomImg:bgImg = {};
theme:theme = {};
lyric:any[] = [];
status:number;
PLAY:number = 1;
PAUSE:number = -1;
STOP:number = 0;
audio = null;
constructor(type:string,count:number){
var me = this;
this.visualizer = new MusicVisualizer({
size:SIZE,
onended:function(){
me.playTo('next');
},visualizer:Render()
});
}
initList(){
var me = this;
$.ajax({
type:'GET',
url:'data/'+this.theme.type+'.php',
dataType:'json',
success:function(data){
me.allSongData = data;
let template:string='';
let arr = Array.prototype.slice.apply(me.allSongData);
for(let i=0;i<arr.length;i++){
template+=`
<li data-idx='${i}'><a href="#"><i>${i+1}</i><span>${arr[i].song_name}-${arr[i].artist}</span></a></li>
`;
}
me.list.html(template);
me.listLi = $('#m-list li');
me.playTo();
}
});
}
playTo(dir?:string){
...
}
playNew(idx:number):void{
...
}
getLyric(url:string):void{
...
}
...
}
之后17年又因为工作关系接触了Egret.js(写的时候意外的发现这家公司倒闭了)引擎,再一次写了TS,虽然是一个完整的TS + Webpack项目,但因为代码的编写范围比较局限,并没有对我TS的掌握有很大的提升。
然后在20年工作的时候,我在新公司内接手了一个由客户端同学+服务端同学开发的前端项目的时候,我震惊了,我直接怀疑我不会TS..
这是一个由React+TS+GraphQL的项目,团队做的是一个NoCode产品,前端涉及到的交互和逻辑非常复杂,咋形容呢,界面就大概长得像"蓝湖"或"Figma"这样复杂吧。然后看任何一行代码都是满满的类型,看任何一个变量都是长长的奇葩,脑子里的CPU每天都在疯狂运转,疯狂理解。
从那以后我就重新认真学习了一遍TS,慢慢的适应了项目,也适应了这门语言。
掐指一算,重新学习再到现在已经有两年半了,有了一点感悟,感觉也可以露出一些鸡脚了。
感悟一
第一个就是巨大的安全感,虽然有时候网上会说写类型很麻烦,但实际上真需要自己写的类型并不算多,现在我遇到要使用工具库的时候我会第一时间找它的定义包,配置或安装完之后再配合官方文档,就可以放心的写,写错的时候都会有巨贴心的错误提醒,而且属性和方法在IDE的配合下点进去都可以看详细的定义,很多时候都不需要翻开文档。
然后就是需要自己写类型的时候,我经历从"好麻烦"到"好方便"两个阶段。为啥呢?
因为我觉得这件事情好麻烦的时候是因为我并不知道我要怎么写定义。对,我说的就是我不会写。即使我已经翻烂并熟读TS的各种类型和泛型的定义、以及清楚的知道Interface与Type的区别~ balabala..
怎么理解?其实就是自己并不清楚自己需要"做什么",一个代码第一行,往往从const component = balabala开始, 我脑子的JS告诉我,先放着,大概要写个展示啥啥的列表。我脑子里的TS会告诉我,我需要一个接收一个数组,里面有时间戳、标题、内容等数据,向外暴露一个onNextPage方法的组件。
当我完成这个组件定义的时候,我似乎完成的不只是这一段代码,仿佛真的是完成一个组件。因为我可以在引用这个组件的地方继续完成我要做的事情。强大的TS类型提醒可以帮助我完成剩下大部分的逻辑编写。
感悟二
一直以来我对服务端同学都被要求编写技术方案这个事情有所羡慕,前端的世界简简单单,没有人被要求也没有人要想求什么。我在网上搜索"前端" "技术方案" "设计"等关键字后,得到的结果都是什么需求分析、流程拆解、5个W、几个How、或是直接几个框架的选型对比。我看完之后还是实在不能理解。因为作为一个已经被产品、设计、后端开发方案都确定的情况下,前端要做的事情就是将他们~~~画出来而已,怎么画?Vue呀、React呀~~~就好了呀?产品的方案就是你的方案呀、再加上设计、后端,这些就是你的方案呀,还要写啥呢?
嗯..好像确实是的,那为什么每次写起来总感觉比预想的难呢?
后来我利用TS找到了适合自己理解的一种技术方案。
下面是一些模拟的伪代码片段,随便开个MarkDown就可以写起来了
假设你要做一个心理测量的量表和测评页面,需要配置问题列表和答案,以及配置的模版
- 第一步,首先我会确定这个需求相关的路由
ts
// NOTE:租户tenant是通过domain转发还是路由中添加path区分?
const Routes = [
{
name: 'User',
path: '/user',
children: [
{
name: 'UserList',
path: 'list'
},
{
name: 'UserDetail',
path: 'detail/:userId'
}
]
},
{
name: 'Scales',
path: '/scales',
children: [
{
name: 'ScalesList',
path: 'list'
},
{
name: 'ScalesEdit',
path: 'edit/:scalesId',
},
{
// NOTE: 编辑量表问题和选项
name: 'ScalesQuestion',
path: 'scalesQuestion/:scalesId'
},
]
},
{
name: 'Evaluation',
path: '/evaluation',
children: [
{
name: 'EvaluationList',
path: 'list'
},
{
name: 'EvaluationDetail',
path: 'detail/:evaluationId'
}
]
},
]
- 第二步,定一个类型文件(并不关心实际语法是否有误, 表示即可)
ts
type Scales = {
id: string
name: string
description: string
instruction:string
questions: Question[]
testingTemplateId: string
status: 'published' | 'edit'
belongs: 'platform' | 'self'
tenantId: string
}
// 从后端获取模版列表
type EvalTemplate = {
name: string
id: string
type: 'total' | 'factor'
factors: Factor[]
params: TemplateParams
normParams: KeyValue
}
type Question = {
id: string
scaleId: string
title: string
options: Option[]
questionType: 'single' | 'multiple'
}
type Answer = {
questionId: string
option?: Option
options?: Option[]
}
type Option = {
content: string
score: number
value: string
}
type ScalesListTable = Array<{
id: string
name: string
belongs: 'platform' | 'self'
}>
...
- 再自行判断是否需要引入一些工具函数
ts
export const enum TenantId {
owner = '0',
xxxHospital = '1'
}
export class Utils {
static getCurrentTenant () => TenantId
static isxxx () => boolean
}
- 最后,就是写一两个需要注意的事项和技术选型,可以是setToken或getToken的注意点、或是是否需要重新写一个Layout,技术选型可以写上这次的xx框架以及需要用到的第三方库,简单点就好。
这样下来,写一个这样的技术方案只需要花上三五分钟就能搞定,基本上能帮我理清这个需求的大纲了。当然如果项目再大一些我会再画一些组件和布局的示意图
总结
这些差不多是本篇文章想分享的所有了。我时常在网上看到很多人黑TS,言语上总是充斥着戾气,像是被TS深深伤害过的人。当然也偶尔会听到一些大佬或团队宣布退出使用TS的新闻,但个人觉得是TS在超大型项目多人协作过程中遇到的高阶问题。一般人也遇不到,TS依然YYDS。