Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork86
A curated list of awesome 🔥 TypeScript Tips 🔥
jellydn/typescript-tips
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A curated list of awesome 🔥 TypeScript Tips 🔥
If you enjoy TypeScript and really want to use Typesafe, you can checkawesome-typesafe
- TypeScript Tips Series
- LooseAutocomplete
- Normal union, a discriminated union, and a type predicate
- Enter satisfies()() 👀
- Use Object.freeze to ensure your objects are readonly at the type level AND the runtime level
- Inversion of control
- Ultimate TypeScript Thread
- Expose type to global with declare global
- Use generics to dynamically specify the number, and type, of arguments to functions
- Adding things to the global scope in TypeScript
- Using 'as const' over enums
- Use assertion functions inside classes
- Compound Components in React are SUPER easy to type in TS
- Four ways to define an object type in TypeScript
- The difference between
anyandunknown - Use TypeScript's
neverfor making sure you hit every scenario - Use TypeScript's
neverto enforce "one or the other" properties on a type - Type Guard in TypeScript by using the
iskeyword in a functions return type - VSCode - quickly add all properties to a typed object in TypeScript with the ts-quickfixes
- VSCode - refactoring your codebase
- 4 TypeScript tips in context of when you would use them. as const, typeof, keyof and template string types
- Enum vs const enums
- Use labeled tuple elements to get better hints from your text editor
- Use
as constafter literals
- Avoid making a property optional when the property isn’t valid in a certain case
- Alias the type's name when conflicts with an existing identifier
- Many optional properties are a code smell
- Extract it from a component using the handy
ComponentProps - Use
keyofgets a union type of all properties of the given object
PackageJson- There are a lot of tools thatplace extra configurations inside thepackage.jsonfile. You can extendPackageJsonto support these additional configurations.Example
importtype{PackageJsonasBasePackageJson}from"type-fest";importtype{Linter}from"eslint";typePackageJson=BasePackageJson&{eslintConfig?:Linter.Config};
There are many advanced types most users don't know about.
Partial<T>-Make all properties inToptional.Example
interfaceNodeConfig{appName:string;port:number;}classNodeAppBuilder{privateconfiguration:NodeConfig={appName:"NodeApp",port:3000,};privateupdateConfig<KeyextendskeyofNodeConfig>(key:Key,value:NodeConfig[Key]){this.configuration[key]=value;}config(config:Partial<NodeConfig>){typeNodeConfigKey=keyofNodeConfig;for(constkeyofObject.keys(config)asNodeConfigKey[]){constupdateValue=config[key];if(updateValue===undefined){continue;}this.updateConfig(key,updateValue);}returnthis;}}// `Partial<NodeConfig>`` allows us to provide only a part of the// NodeConfig interface.newNodeAppBuilder().config({appName:"ToDoApp"});
Required<T>-Make all properties inTrequired.Example
interfaceContactForm{email?:string;message?:string;}functionsubmitContactForm(formData:Required<ContactForm>){// Send the form data to the server.}submitContactForm({email:"ex@mple.com",message:"Hi! Could you tell me more about�",});// TypeScript error: missing property 'message'submitContactForm({email:"ex@mple.com",});
Readonly<T>-Make all properties inTreadonly.Example
enumLogLevel{Off,Debug,Error,Fatal,}interfaceLoggerConfig{name:string;level:LogLevel;}classLogger{config:Readonly<LoggerConfig>;constructor({ name, level}:LoggerConfig){this.config={ name, level};Object.freeze(this.config);}}constconfig:LoggerConfig={name:"MyApp",level:LogLevel.Debug,};constlogger=newLogger(config);// TypeScript Error: cannot assign to read-only property.logger.config.level=LogLevel.Error;// We are able to edit config variable as we please.config.level=LogLevel.Error;
Pick<T, K>-FromT, pick a set of properties whose keys are in the unionK.Example
interfaceArticle{title:string;thumbnail:string;content:string;}// Creates new type out of the `Article` interface composed// from the Articles' two properties: `title` and `thumbnail`.// `ArticlePreview = {title: string; thumbnail: string}`typeArticlePreview=Pick<Article,"title"|"thumbnail">;// Render a list of articles using only title and description.functionrenderArticlePreviews(previews:ArticlePreview[]):HTMLElement{constarticles=document.createElement("div");for(constpreviewofpreviews){// Append preview to the articles.}returnarticles;}constarticles=renderArticlePreviews([{title:"TypeScript tutorial!",thumbnail:"/assets/ts.jpg",},]);
Record<K, T>-Construct a type with a set of propertiesKof typeT.Example
// Positions of employees in our company.typeMemberPosition="intern"|"developer"|"tech-lead";// Interface describing properties of a single employee.interfaceEmployee{firstName:string;lastName:string;yearsOfExperience:number;}// Create an object that has all possible `MemberPosition` values set as keys.// Those keys will store a collection of Employees of the same position.constteam:Record<MemberPosition,Employee[]>={intern:[],developer:[],"tech-lead":[],};// Our team has decided to help John with his dream of becoming Software Developer.team.intern.push({firstName:"John",lastName:"Doe",yearsOfExperience:0,});// `Record` forces you to initialize all of the property keys.// TypeScript Error: "tech-lead" property is missingconstteamEmpty:Record<MemberPosition,null>={intern:null,developer:null,};
Exclude<T, U>-Exclude fromTthose types that are assignable toU.Example
interfaceServerConfig{port:null|string|number;}typeRequestHandler=(request:Request,response:Response)=>void;// Exclude `null` type from `null | string | number`.// In case the port is equal to `null`, we will use default value.functiongetPortValue(port:Exclude<ServerConfig["port"],null>):number{if(typeofport==="string"){returnparseInt(port,10);}returnport;}functionstartServer(handler:RequestHandler,config:ServerConfig):void{constserver=require("http").createServer(handler);constport=config.port===null ?3000 :getPortValue(config.port);server.listen(port);}
Extract<T, U>-Extract fromTthose types that are assignable toU.Example
declarefunctionuniqueId():number;constID=Symbol("ID");interfacePerson{[ID]:number;name:string;age:number;}// Allows changing the person data as long as the property key is of string type.functionchangePersonData<ObjextendsPerson,KeyextendsExtract<keyofPerson,string>,ValueextendsObj[Key]>(obj:Obj,key:Key,value:Value):void{obj[key]=value;}// Tiny Andrew was born.constandrew={[ID]:uniqueId(),name:"Andrew",age:0,};// Cool, we're fine with that.changePersonData(andrew,"name","Pony");// Goverment didn't like the fact that you wanted to change your identity.changePersonData(andrew,ID,uniqueId());
NonNullable<T>-ExcludenullandundefinedfromT.Example
Works withstrictNullChecksset totrue.typePortNumber=string|number|null;/** Part of a class definition that is used to build a server */classServerBuilder{portNumber!:NonNullable<PortNumber>;port(this:ServerBuilder,port:PortNumber):ServerBuilder{if(port==null){this.portNumber=8000;}else{this.portNumber=port;}returnthis;}}constserverBuilder=newServerBuilder();serverBuilder.port("8000")// portNumber = '8000'.port(null)// portNumber = 8000.port(3000);// portNumber = 3000// TypeScript errorserverBuilder.portNumber=null;
Parameters<T>-Obtain the parameters of a function type in a tuple.Example
functionshuffle(input:any[]):void{// Mutate array randomly changing its' elements indexes.}functioncallNTimes<Fnextends(...args:any[])=>any>(func:Fn,callCount:number){// Type that represents the type of the received function parameters.typeFunctionParameters=Parameters<Fn>;returnfunction(...args:FunctionParameters){for(leti=0;i<callCount;i++){func(...args);}};}constshuffleTwice=callNTimes(shuffle,2);
ConstructorParameters<T>-Obtain the parameters of a constructor function type in a tuple.Example
classArticleModel{title:string;content?:string;constructor(title:string){this.title=title;}}classInstanceCache<Textendsnew(...args:any[])=>any>{privateClassConstructor:T;privatecache:Map<string,InstanceType<T>>=newMap();constructor(ctr:T){this.ClassConstructor=ctr;}getInstance(...args:ConstructorParameters<T>):InstanceType<T>{consthash=this.calculateArgumentsHash(...args);constexistingInstance=this.cache.get(hash);if(existingInstance!==undefined){returnexistingInstance;}returnnewthis.ClassConstructor(...args);}privatecalculateArgumentsHash(...args:any[]):string{// Calculate hash.return"hash";}}constarticleCache=newInstanceCache(ArticleModel);constamazonArticle=articleCache.getInstance("Amazon forests burining!");
ReturnType<T>-Obtain the return type of a function type.Example
/** Provides every element of the iterable `iter` into the `callback` function and stores the results in an array. */functionmapIter<Elem,Funcextends(elem:Elem)=>any,RetextendsReturnType<Func>>(iter:Iterable<Elem>,callback:Func):Ret[]{constmapped:Ret[]=[];for(constelemofiter){mapped.push(callback(elem));}returnmapped;}constsetObject:Set<string>=newSet();constmapObject:Map<number,string>=newMap();mapIter(setObject,(value:string)=>value.indexOf("Foo"));// number[]mapIter(mapObject,([key,value]:[number,string])=>{returnkey%2===0 ?value :"Odd";});// string[]
InstanceType<T>-Obtain the instance type of a constructor function type.Example
classIdleService{doNothing():void{}}classNews{title:string;content:string;constructor(title:string,content:string){this.title=title;this.content=content;}}constinstanceCounter:Map<Function,number>=newMap();interfaceConstructor{new(...args:any[]):any;}// Keep track how many instances of `Constr` constructor have been created.functiongetInstance<ConstrextendsConstructor,ArgsextendsConstructorParameters<Constr>>(constructor:Constr, ...args:Args):InstanceType<Constr>{letcount=instanceCounter.get(constructor)||0;constinstance=newconstructor(...args);instanceCounter.set(constructor,count+1);console.log(`Created${count+1} instances of${Constr.name} class`);returninstance;}constidleService=getInstance(IdleService);// Will log: `Created 1 instances of IdleService class`constnewsEntry=getInstance(News,"New ECMAScript proposals!","Last month...");// Will log: `Created 1 instances of News class`
Omit<T, K>-Constructs a type by picking all properties from T and then removing K.Example
interfaceAnimal{imageUrl:string;species:string;images:string[];paragraphs:string[];}// Creates new type with all properties of the `Animal` interface// except 'images' and 'paragraphs' properties. We can use this// type to render small hover tooltip for a wiki entry list.typeAnimalShortInfo=Omit<Animal,"images"|"paragraphs">;functionrenderAnimalHoverInfo(animals:AnimalShortInfo[]):HTMLElement{constcontainer=document.createElement("div");// Internal implementation.returncontainer;}
Uppercase<S extends string>-Transforms every character in a string into uppercase.Example
typeT=Uppercase<"hello">;// 'HELLO'typeT2=Uppercase<"foo"|"bar">;// 'FOO' | 'BAR'typeT3<Sextendsstring>=Uppercase<`aB${S}`>;typeT4=T3<"xYz">;// 'ABXYZ'typeT5=Uppercase<string>;// stringtypeT6=Uppercase<any>;// anytypeT7=Uppercase<never>;// nevertypeT8=Uppercase<42>;// Error, type 'number' does not satisfy the constraint 'string'
Lowercase<S extends string>-Transforms every character in a string into lowercase.Example
typeT=Lowercase<"HELLO">;// 'hello'typeT2=Lowercase<"FOO"|"BAR">;// 'foo' | 'bar'typeT3<Sextendsstring>=Lowercase<`aB${S}`>;typeT4=T3<"xYz">;// 'abxyz'typeT5=Lowercase<string>;// stringtypeT6=Lowercase<any>;// anytypeT7=Lowercase<never>;// nevertypeT8=Lowercase<42>;// Error, type 'number' does not satisfy the constraint 'string'
Capitalize<S extends string>-Transforms the first character in a string into uppercase.Example
typeT=Capitalize<"hello">;// 'Hello'typeT2=Capitalize<"foo"|"bar">;// 'Foo' | 'Bar'typeT3<Sextendsstring>=Capitalize<`aB${S}`>;typeT4=T3<"xYz">;// 'ABxYz'typeT5=Capitalize<string>;// stringtypeT6=Capitalize<any>;// anytypeT7=Capitalize<never>;// nevertypeT8=Capitalize<42>;// Error, type 'number' does not satisfy the constraint 'string'
Uncapitalize<S extends string>-Transforms the first character in a string into lowercase.Example
typeT=Uncapitalize<"Hello">;// 'hello'typeT2=Uncapitalize<"Foo"|"Bar">;// 'foo' | 'bar'typeT3<Sextendsstring>=Uncapitalize<`AB${S}`>;typeT4=T3<"xYz">;// 'aBxYz'typeT5=Uncapitalize<string>;// stringtypeT6=Uncapitalize<any>;// anytypeT7=Uncapitalize<never>;// nevertypeT8=Uncapitalize<42>;// Error, type 'number' does not satisfy the constraint 'string'
You can find some examples in theTypeScript docs.
Contributions welcome! Read thecontribution guidelinesfirst.
Create .envrc and fill the value then Usetweet-to-markdown
# .envrcexport TTM_API_KEY=YOUR_API_KEY
Then run thedirenv command
direnv allow.And, generate markdown from a twitter url
npx tweet-to-markdown -p notes https://twitter.com/mattpocockuk/status/1509964736275927042\?s\=20\&t\=sA-g5MNM5TPjN6Ozs1qxgA
Then save video if available
npx twt-dl-cli@latest https://twitter.com/mattpocockuk/status/1592130978234900484
Finally, add theThread Reader App at the end with below format.
[Thread by@USERNAME on Threadify Reader App](https://threadify.productsway.com/thread/STATUS_ID)
NOTE: I have sent a pull request about this step totweet-to-markdown repository:feat: add Thread Reader App link and the end #19 Might not need this step if this PR is accepted.
This project is made by community and especially the wonderful people and projects listed in this document
- sindresorhus/type-fest: for 2 sections (Extending existing type, Built-in types)
- kbravh/tweet-to-markdown: A command line tool to convert Tweets to Markdown.
- jellydn/threadify-plus: ThreadifyPlus is a simple and easy-to-use tool that helps users read and share Twitter threads with ease. (WIP)
- egoist/download-twitter-video : The easiest way to download any Twitter video
- Matt Pocock
✈️ Modern Frontends - Wes Bos
- Erik Rasmussen
- Carlos Caballero
- Ankita Kulkarni
- Minko Gechev (@mgechev@mstdn.social)
- Cory House
- Tomek Sułkowski
- Sebastien Lorber
- Steve (Builder.io)
- StackBlitz
👤Huynh Duc Dung
- Website:https://productsway.com/
- Twitter:@jellydn
- Github:@jellydn
Give a ⭐️ if this project helped you!
About
A curated list of awesome 🔥 TypeScript Tips 🔥
Topics
Resources
Code of conduct
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors3
Uh oh!
There was an error while loading.Please reload this page.