TSConf 2021: TypeScript Maturity and Enterprise Adoption
Table of Contents
TSConf 2021 | Virtual Conference
TSConf 2021 continued the virtual format, bringing together TypeScript developers worldwide to explore the latest features and best practices.
Presentation
Control Flow Analysis Improvements
// TypeScript 4.4 Control Flow Analysis
function example(x: string | number | boolean) {
if (typeof x === "string") {
console.log(x.toUpperCase()); // x is string
} else if (typeof x === "number") {
console.log(x.toFixed(2)); // x is number
} else {
console.log(x); // x is boolean
}
}
// Aliased conditions now work
function aliasedCheck(x: string | number) {
const isString = typeof x === "string";
if (isString) {
console.log(x.toUpperCase()); // x is narrowed to string
}
}
Template Literal Type Inference
// Infer within template literal types
type ExtractRouteParams<T extends string> =
T extends `${infer _Start}:${infer Param}/${infer Rest}`
? Param | ExtractRouteParams<Rest>
: T extends `${infer _Start}:${infer Param}`
? Param
: never;
type Params = ExtractRouteParams<"/users/:userId/posts/:postId">;
// type Params = "userId" | "postId"
Sessions
TypeScript 4.4 and 4.5 Features
// Static Index Signatures
interface StringByString {
[key: string]: string;
}
// Exact optional property types
interface Config {
name: string;
value?: string; // undefined is not assignable by default with exactOptionalPropertyTypes
}
// Awaited Type built-in
type T = Awaited<Promise<Promise<string>>>; // string
Abstract Construct Signatures
// TypeScript 4.2 Abstract Construct Signatures
abstract class Shape {
abstract getArea(): number;
}
type Constructor<T> = abstract new (...args: any[]) => T;
function createInstance<T extends Shape>(
Ctor: Constructor<T>,
...args: ConstructorParameters<typeof Ctor>
): T {
// This allows abstract classes to be passed
throw new Error("Cannot instantiate abstract class");
}
ES Modules in Node.js with TypeScript
// package.json
{
"type": "module",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}
}
// tsconfig.json
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true
}
}
// Usage with .js extension required
import { helper } from "./utils.js";
Type-Safe API Design
// Branded types for type safety
type UserId = string & { readonly brand: unique symbol };
type OrderId = string & { readonly brand: unique symbol };
function createUserId(id: string): UserId {
return id as UserId;
}
function createOrderId(id: string): OrderId {
return id as OrderId;
}
function getUser(id: UserId): void {
// Only accepts UserId, not OrderId or plain string
}
const userId = createUserId("user-123");
const orderId = createOrderId("order-456");
getUser(userId); // OK
// getUser(orderId); // Error: Argument of type 'OrderId' is not assignable
Testing TypeScript Applications
// Type-safe testing with vitest
import { describe, it, expect, vi } from 'vitest';
interface UserService {
getUser(id: string): Promise<User>;
}
const mockUserService: UserService = {
getUser: vi.fn().mockResolvedValue({ id: '1', name: 'Test User' })
};
describe('UserController', () => {
it('should fetch user by id', async () => {
const user = await mockUserService.getUser('1');
expect(user.name).toBe('Test User');
});
});
Performance and Bundle Optimization
// Tree-shaking friendly exports
// utils/index.ts
export { formatDate } from './date.js';
export { formatCurrency } from './currency.js';
// Avoid namespace exports for tree-shaking
// Instead of: export * as utils from './utils';
// Use individual exports
// Type-only imports for build optimization
import type { User } from './types.js';
import { validateUser } from './validators.js';
Conference Highlights
Enterprise TypeScript
Discussions on TypeScript adoption at scale, including migration strategies and maintaining large TypeScript codebases.
Community Tools
Showcases of community tools including tsc alternatives, linting configurations, and development workflows.
Future of TypeScript
Previews of upcoming features and the TypeScript roadmap, with input from the TypeScript team.