Loading post...
© 2026 Chiatiah Rayan Nguea All rights reserved. console.log("Made with passion") {
"developer": "Chiatiah Rayan",
"stack": [
"React",
"Next.js",
"TypeScript",
"Node",
"Golang"
],
"status": "Always learning",
"coffee": true,
"bugs": 0, // (hopefully)
"uptime": "99.99%",
"lastDeployed": "February 7th, 2026"
}
Back to ArticlesTypeScript Type System Wizardry: From Generics to Template Literal Types
January 16th, 2026 • 3 minute read
Unlock the full power of TypeScript's type system with advanced patterns that make impossible states impossible
TS Type Safety Advocate
rayanstudio
TypeScript's type system is Turing complete. Let that sink in. You can compute types at compile time.
Template Literal Types
One of the most elegant features introduced in TS 4.1:
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
type Route = '/users' | '/posts' | '/comments'
type Endpoint = ` ${ HTTPMethod } ${ Route } `
// Result: "GET /users" | "GET /posts" | ... (16 combinations)
Code Syntax Highlighting
Building a Type-Safe Router type RouteParams = T extends ` ${ infer _Start } : ${ infer Param } / ${ infer Rest } `
? { [ K in Param | keyof RouteParams ] : string }
: T extends ` ${ infer _Start } : ${ infer
Branded Types Prevent primitive obsession:
type Brand = K & { __brand : T }
type UserId = Brand
type PostId = Brand
function getUser ( id : UserId ) {
/* ... */
}
function getPost ( id : PostId ) {
/* ... */
}
Conditional Types The Swiss Army knife of type manipulation:
type UnwrapPromise = T extends Promise ? U : T
type A = UnwrapPromise < Promise > // string
type B = UnwrapPromise // number
// Deep readonly implementation
type DeepReadonly = {
readonly [ P in keyof T ] : T [
Mapped Types with Key Remapping type Getters = {
[ K in keyof T as `get ${ Capitalize } ` ] : () => T [ K ]
}
interface User {
name : string
age : number
}
type UserGetters = Getters
// Result:
The Discriminated Union Pattern type Success = {
status : 'success'
data : T
}
type Failure = {
status : 'error'
error : Error
}
type Loading = {
status : 'loading'
}
type Result = Success | Failure | Loading
Utility Type: Builder Pattern TypeScript Type System Wizardry: From Generics to Template Literal Types — Article - Chiatiah Rayan's Article
type Builder = {
[ K in keyof T ] - ? : ( value : T [ K ]) => Builder
} & {
build () : T
}
function createBuilder () : Builder {
const data = {} as
The type system is your friend. Make impossible states impossible.
Param
}
`
? { [ K in Param ] : string }
: {}
type UserRoute = '/users/:userId/posts/:postId'
type Params = RouteParams
// Result: { userId: string; postId: string }
function navigate ( route : T , params : RouteParams ) : void {
// Type-safe navigation!
}
navigate ( '/users/:userId/posts/:postId' , {
userId : '123' ,
postId : '456' ,
}) // ✅ Works
navigate ( '/users/:userId/posts/:postId' , {
userId : '123' ,
// ❌ Error: Property 'postId' is missing
})
const userId = 'user123' as UserId
const postId = 'post456' as PostId
getUser ( userId ) // ✅
getUser ( postId ) // ❌ Type error!
P
]
extends
object
?
DeepReadonly
:
T
[
P
]
}
interface Config {
database : {
host : string
port : number
}
}
type ImmutableConfig = DeepReadonly
// All nested properties are readonly
// {
// getName: () => string;
// getAge: () => number;
// }
function handleResult ( result : Result ) {
switch ( result . status ) {
case 'success' :
// TypeScript knows result.data exists
console . log ( result . data )
break
case 'error' :
// TypeScript knows result.error exists
console . error ( result . error )
break
case 'loading' :
// TypeScript knows result has no data or error
console . log ( 'Loading...' )
break
}
}
T
const builder = new Proxy ({} as Builder , {
get ( _ , prop ) {
if ( prop === 'build' ) {
return () => data
}
return ( value : unknown ) => {
;( data as any )[ prop ] = value
return builder
}
},
})
return builder
}
interface User {
name : string
age : number
email : string
}
const user = createBuilder ()
. name ( 'Alice' )
. age ( 30 )
. email ( 'alice@example.com' )
. build ()