or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-traversal.mdcode-analysis.mdcontrol-flow.mdindex.mdnode-typeguards.mdtext-processing.mdtype-guards.mdtype-utilities.mdvariable-usage.md

type-utilities.mddocs/

0

# Type System Utilities

1

2

Advanced type system analysis including type assignability checking, property analysis, class type inspection, type manipulation utilities, and comprehensive type system operations for deep TypeScript compiler integration.

3

4

## Capabilities

5

6

### Type Assignability Analysis

7

8

Utilities for checking type compatibility and assignability relationships.

9

10

```typescript { .api }

11

/**

12

* Check if type is assignable to number

13

* @param checker - Type checker instance

14

* @param type - Type to check

15

* @returns true if type is assignable to number

16

*/

17

function isTypeAssignableToNumber(checker: ts.TypeChecker, type: ts.Type): boolean;

18

19

/**

20

* Check if type is assignable to string

21

* @param checker - Type checker instance

22

* @param type - Type to check

23

* @returns true if type is assignable to string

24

*/

25

function isTypeAssignableToString(checker: ts.TypeChecker, type: ts.Type): boolean;

26

27

/**

28

* Check if type is thenable (has then method)

29

* @param checker - Type checker instance

30

* @param node - Node for context

31

* @param type - Type to check

32

* @returns true if type is thenable (Promise-like)

33

*/

34

function isThenableType(checker: ts.TypeChecker, node: ts.Node, type: ts.Type): boolean;

35

36

/**

37

* Check if type is thenable based on expression

38

* @param checker - Type checker instance

39

* @param node - Expression node

40

* @param type - Optional type (inferred from node if not provided)

41

* @returns true if type is thenable

42

*/

43

function isThenableType(checker: ts.TypeChecker, node: ts.Expression, type?: ts.Type): boolean;

44

```

45

46

### Type Classification

47

48

Utilities for classifying and analyzing type characteristics.

49

50

```typescript { .api }

51

/**

52

* Check if type is falsy (null, undefined, false, 0, "", etc.)

53

* @param type - Type to check

54

* @returns true if type is always falsy

55

*/

56

function isFalsyType(type: ts.Type): boolean;

57

58

/**

59

* Check if type is specific boolean literal type

60

* @param type - Type to check

61

* @param literal - Boolean value to match

62

* @returns true if type is the specified boolean literal

63

*/

64

function isBooleanLiteralType(type: ts.Type, literal: boolean): boolean;

65

66

/**

67

* Check if object type is empty (no properties)

68

* @param type - Type to check

69

* @returns true if type is empty object type

70

*/

71

function isEmptyObjectType(type: ts.Type): type is ts.ObjectType;

72

```

73

74

### Optional Chaining and Optionality

75

76

Utilities for handling optional chaining and optional types.

77

78

```typescript { .api }

79

/**

80

* Remove optionality from type (T | undefined -> T)

81

* @param checker - Type checker instance

82

* @param type - Type to process

83

* @returns Type with optionality removed

84

*/

85

function removeOptionalityFromType(checker: ts.TypeChecker, type: ts.Type): ts.Type;

86

87

/**

88

* Remove optional chaining undefined marker type

89

* @param checker - Type checker instance

90

* @param type - Type to process

91

* @returns Type with optional chaining marker removed

92

*/

93

function removeOptionalChainingUndefinedMarkerType(checker: ts.TypeChecker, type: ts.Type): ts.Type;

94

95

/**

96

* Check if type is optional chaining undefined marker

97

* @param checker - Type checker instance

98

* @param type - Type to check

99

* @returns true if type is optional chaining marker

100

*/

101

function isOptionalChainingUndefinedMarkerType(checker: ts.TypeChecker, type: ts.Type): boolean;

102

```

103

104

### Union and Intersection Type Analysis

105

106

Utilities for working with composite types.

107

108

```typescript { .api }

109

/**

110

* Get constituent types of a union type

111

* @param type - Union type to decompose

112

* @returns Array of union member types

113

*/

114

function unionTypeParts(type: ts.Type): ts.Type[];

115

116

/**

117

* Get constituent types of an intersection type

118

* @param type - Intersection type to decompose

119

* @returns Array of intersection member types

120

*/

121

function intersectionTypeParts(type: ts.Type): ts.Type[];

122

123

/**

124

* Test some parts of a union or intersection type

125

* @param type - Type to test

126

* @param predicate - Type predicate function

127

* @param cb - Callback to test each part

128

* @returns true if callback returns true for any part

129

*/

130

function someTypePart(

131

type: ts.Type,

132

predicate: (t: ts.Type) => t is ts.UnionOrIntersectionType,

133

cb: (t: ts.Type) => boolean

134

): boolean;

135

```

136

137

### Property Analysis

138

139

Utilities for analyzing type properties and symbols.

140

141

```typescript { .api }

142

/**

143

* Get property symbol from type by name

144

* @param type - Type to search

145

* @param name - Property name to find

146

* @returns Property symbol if found

147

*/

148

function getPropertyOfType(type: ts.Type, name: ts.__String): ts.Symbol | undefined;

149

150

/**

151

* Get well-known symbol property from type

152

* @param type - Type to search

153

* @param wellKnownSymbolName - Well-known symbol name (e.g., 'iterator')

154

* @param checker - Type checker instance

155

* @returns Property symbol if found

156

*/

157

function getWellKnownSymbolPropertyOfType(

158

type: ts.Type,

159

wellKnownSymbolName: string,

160

checker: ts.TypeChecker

161

): ts.Symbol | undefined;

162

163

/**

164

* Check if property is readonly in type

165

* @param type - Type containing property

166

* @param name - Property name

167

* @param checker - Type checker instance

168

* @returns true if property is readonly

169

*/

170

function isPropertyReadonlyInType(

171

type: ts.Type,

172

name: ts.__String,

173

checker: ts.TypeChecker

174

): boolean;

175

176

/**

177

* Check if symbol has readonly declaration

178

* @param symbol - Symbol to check

179

* @param checker - Type checker instance

180

* @returns true if symbol is declared readonly

181

*/

182

function symbolHasReadonlyDeclaration(symbol: ts.Symbol, checker: ts.TypeChecker): boolean;

183

184

/**

185

* Get property name from type (for computed properties)

186

* @param type - Type representing property name

187

* @returns Property name information if extractable

188

*/

189

function getPropertyNameFromType(type: ts.Type): PropertyName | undefined;

190

191

/**

192

* Property name information interface

193

*/

194

interface PropertyName {

195

displayName: string;

196

symbolName: ts.__String;

197

}

198

```

199

200

### Class Type Analysis

201

202

Specialized utilities for analyzing class types and inheritance.

203

204

```typescript { .api }

205

/**

206

* Get symbol of class-like declaration

207

* @param node - Class-like declaration

208

* @param checker - Type checker instance

209

* @returns Class symbol

210

*/

211

function getSymbolOfClassLikeDeclaration(

212

node: ts.ClassLikeDeclaration,

213

checker: ts.TypeChecker

214

): ts.Symbol;

215

216

/**

217

* Get constructor type of class-like declaration

218

* @param node - Class-like declaration

219

* @param checker - Type checker instance

220

* @returns Constructor type

221

*/

222

function getConstructorTypeOfClassLikeDeclaration(

223

node: ts.ClassLikeDeclaration,

224

checker: ts.TypeChecker

225

): ts.Type;

226

227

/**

228

* Get instance type of class-like declaration

229

* @param node - Class-like declaration

230

* @param checker - Type checker instance

231

* @returns Instance type

232

*/

233

function getInstanceTypeOfClassLikeDeclaration(

234

node: ts.ClassLikeDeclaration,

235

checker: ts.TypeChecker

236

): ts.Type;

237

238

/**

239

* Get base class member symbol for class element

240

* @param node - Class member declaration

241

* @param checker - Type checker instance

242

* @returns Base class member symbol if found

243

*/

244

function getBaseClassMemberOfClassElement(

245

node: ts.PropertyDeclaration | ts.MethodDeclaration | ts.AccessorDeclaration,

246

checker: ts.TypeChecker

247

): ts.Symbol | undefined;

248

```

249

250

### Signature Analysis

251

252

Utilities for analyzing function and method signatures.

253

254

```typescript { .api }

255

/**

256

* Get call signatures from type

257

* @param type - Type to analyze

258

* @returns Array of call signatures

259

*/

260

function getCallSignaturesOfType(type: ts.Type): ReadonlyArray<ts.Signature>;

261

```

262

263

### Iterator Type Analysis

264

265

Utilities for analyzing iterator types and async iterators.

266

267

```typescript { .api }

268

/**

269

* Extract yield result type from iterator result type

270

* @param type - Iterator result type

271

* @param node - Node for context

272

* @param checker - Type checker instance

273

* @returns Yield result type

274

*/

275

function getIteratorYieldResultFromIteratorResult(

276

type: ts.Type,

277

node: ts.Node,

278

checker: ts.TypeChecker

279

): ts.Type;

280

```

281

282

**Usage Examples:**

283

284

```typescript

285

import * as ts from "typescript";

286

import {

287

isTypeAssignableToNumber,

288

isTypeAssignableToString,

289

isFalsyType,

290

unionTypeParts,

291

getPropertyOfType,

292

getSymbolOfClassLikeDeclaration,

293

getCallSignaturesOfType,

294

isThenableType

295

} from "tsutils/util";

296

297

// Type assignability analysis

298

function analyzeTypeCompatibility(checker: ts.TypeChecker, type: ts.Type) {

299

if (isTypeAssignableToNumber(checker, type)) {

300

console.log("Type is assignable to number");

301

}

302

303

if (isTypeAssignableToString(checker, type)) {

304

console.log("Type is assignable to string");

305

}

306

307

if (isFalsyType(type)) {

308

console.log("Type is always falsy");

309

}

310

}

311

312

// Union type analysis

313

function analyzeUnionType(checker: ts.TypeChecker, type: ts.Type) {

314

if (type.flags & ts.TypeFlags.Union) {

315

const parts = unionTypeParts(type);

316

console.log(`Union has ${parts.length} parts:`);

317

318

parts.forEach((part, index) => {

319

console.log(` ${index}: ${checker.typeToString(part)}`);

320

321

if (isTypeAssignableToString(checker, part)) {

322

console.log(` Part ${index} is string-like`);

323

}

324

});

325

}

326

}

327

328

// Property analysis

329

function analyzeTypeProperties(checker: ts.TypeChecker, type: ts.Type) {

330

if (type.symbol && type.symbol.members) {

331

console.log("Type properties:");

332

333

type.symbol.members.forEach((symbol, name) => {

334

const property = getPropertyOfType(type, name);

335

if (property) {

336

console.log(` ${name}: ${checker.typeToString(checker.getTypeOfSymbolAtLocation(property, property.valueDeclaration!))}`);

337

338

if (isPropertyReadonlyInType(type, name, checker)) {

339

console.log(` (readonly)`);

340

}

341

}

342

});

343

}

344

}

345

346

// Class analysis

347

function analyzeClass(checker: ts.TypeChecker, classDecl: ts.ClassDeclaration) {

348

const symbol = getSymbolOfClassLikeDeclaration(classDecl, checker);

349

const constructorType = getConstructorTypeOfClassLikeDeclaration(classDecl, checker);

350

const instanceType = getInstanceTypeOfClassLikeDeclaration(classDecl, checker);

351

352

console.log(`Class: ${symbol.name}`);

353

console.log(`Constructor type: ${checker.typeToString(constructorType)}`);

354

console.log(`Instance type: ${checker.typeToString(instanceType)}`);

355

356

// Analyze class members

357

classDecl.members.forEach(member => {

358

if (ts.isPropertyDeclaration(member) || ts.isMethodDeclaration(member) || ts.isGetAccessorDeclaration(member)) {

359

const baseSymbol = getBaseClassMemberOfClassElement(member, checker);

360

if (baseSymbol) {

361

console.log(`Member ${member.name?.getText()} overrides base class member`);

362

}

363

}

364

});

365

}

366

367

// Function type analysis

368

function analyzeFunctionType(checker: ts.TypeChecker, type: ts.Type) {

369

const signatures = getCallSignaturesOfType(type);

370

371

if (signatures.length > 0) {

372

console.log(`Function has ${signatures.length} call signature(s):`);

373

374

signatures.forEach((sig, index) => {

375

const sigString = checker.signatureToString(sig);

376

console.log(` ${index}: ${sigString}`);

377

378

const returnType = sig.getReturnType();

379

if (isThenableType(checker, sig.declaration!, returnType)) {

380

console.log(` Returns Promise-like type`);

381

}

382

});

383

}

384

}

385

386

// Promise/thenable analysis

387

function analyzeAsyncTypes(checker: ts.TypeChecker, node: ts.Expression) {

388

const type = checker.getTypeAtLocation(node);

389

390

if (isThenableType(checker, node, type)) {

391

console.log("Expression is thenable (Promise-like)");

392

393

// Try to get the resolved type

394

const thenProperty = getPropertyOfType(type, 'then' as ts.__String);

395

if (thenProperty) {

396

const thenType = checker.getTypeOfSymbolAtLocation(thenProperty, node);

397

console.log(`Then method type: ${checker.typeToString(thenType)}`);

398

}

399

}

400

}

401

402

// Complex type analysis combining multiple utilities

403

function performDeepTypeAnalysis(checker: ts.TypeChecker, type: ts.Type, node: ts.Node) {

404

console.log(`\nAnalyzing type: ${checker.typeToString(type)}`);

405

406

// Basic classification

407

if (isFalsyType(type)) {

408

console.log(" Type is falsy");

409

}

410

411

if (isEmptyObjectType(type)) {

412

console.log(" Type is empty object");

413

}

414

415

// Composite type analysis

416

if (type.flags & ts.TypeFlags.Union) {

417

const parts = unionTypeParts(type);

418

console.log(` Union with ${parts.length} parts`);

419

420

const stringParts = parts.filter(p => isTypeAssignableToString(checker, p));

421

const numberParts = parts.filter(p => isTypeAssignableToNumber(checker, p));

422

423

console.log(` String-assignable parts: ${stringParts.length}`);

424

console.log(` Number-assignable parts: ${numberParts.length}`);

425

}

426

427

// Callable analysis

428

const signatures = getCallSignaturesOfType(type);

429

if (signatures.length > 0) {

430

console.log(` Callable with ${signatures.length} signature(s)`);

431

432

const asyncSignatures = signatures.filter(sig => {

433

const returnType = sig.getReturnType();

434

return isThenableType(checker, node, returnType);

435

});

436

437

if (asyncSignatures.length > 0) {

438

console.log(` ${asyncSignatures.length} async signature(s)`);

439

}

440

}

441

}

442

```

443

444

**Advanced Use Cases:**

445

446

1. **Type-aware Refactoring**: Understanding type relationships for safe code transformations

447

2. **API Compatibility Checking**: Verifying type compatibility across API versions

448

3. **Generic Type Resolution**: Working with complex generic types and constraints

449

4. **Promise/Async Analysis**: Detecting and analyzing asynchronous code patterns

450

5. **Class Hierarchy Analysis**: Understanding inheritance and member overrides

451

6. **Property Mutation Detection**: Identifying readonly vs mutable properties

452

7. **Type Narrowing**: Building sophisticated type guards and narrowing logic

453

8. **Iterator Pattern Analysis**: Working with iterables and async iterables