or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

builtin-types.mdindex.mdproperty-types.mdsymbol-analysis.mdtype-analysis.mdtype-constraints.mdtype-predicates.mdtype-safety.mdtype-specifiers.md

symbol-analysis.mddocs/

0

# Symbol and Declaration Analysis

1

2

Tools for working with TypeScript symbols, declarations, and their relationships to source files and libraries. These utilities help understand the origin and context of types and values in TypeScript code.

3

4

## Capabilities

5

6

### Declaration Resolution

7

8

Functions for finding and analyzing TypeScript declarations.

9

10

```typescript { .api }

11

/**

12

* Gets the declaration for the given variable

13

*/

14

function getDeclaration(

15

services: ParserServicesWithTypeInformation,

16

node: TSESTree.Node

17

): ts.Declaration | null;

18

```

19

20

**Usage Examples:**

21

22

```typescript

23

import { getDeclaration } from "@typescript-eslint/type-utils";

24

25

// In an ESLint rule analyzing variable declarations

26

export default {

27

create(context) {

28

const services = context.parserServices;

29

30

return {

31

Identifier(node) {

32

const declaration = getDeclaration(services, node);

33

34

if (declaration) {

35

// Analyze the declaration

36

switch (declaration.kind) {

37

case ts.SyntaxKind.VariableDeclaration:

38

console.log("Variable declaration found");

39

break;

40

case ts.SyntaxKind.FunctionDeclaration:

41

console.log("Function declaration found");

42

break;

43

case ts.SyntaxKind.ClassDeclaration:

44

console.log("Class declaration found");

45

break;

46

case ts.SyntaxKind.InterfaceDeclaration:

47

console.log("Interface declaration found");

48

break;

49

case ts.SyntaxKind.TypeAliasDeclaration:

50

console.log("Type alias declaration found");

51

break;

52

}

53

54

// Check declaration location

55

const sourceFile = declaration.getSourceFile();

56

console.log(`Declared in: ${sourceFile.fileName}`);

57

}

58

}

59

};

60

}

61

};

62

```

63

64

### Symbol Origin Analysis

65

66

Functions for determining where symbols and types come from.

67

68

```typescript { .api }

69

/**

70

* Checks if a symbol comes from TypeScript's default library

71

*/

72

function isSymbolFromDefaultLibrary(

73

program: ts.Program,

74

symbol: ts.Symbol | undefined

75

): boolean;

76

```

77

78

**Usage Examples:**

79

80

```typescript

81

import { isSymbolFromDefaultLibrary } from "@typescript-eslint/type-utils";

82

83

// In an ESLint rule checking for built-in vs user-defined types

84

export default {

85

create(context) {

86

const services = context.parserServices;

87

const program = services.program;

88

const checker = program.getTypeChecker();

89

90

return {

91

TSTypeReference(node) {

92

const tsNode = services.esTreeNodeToTSNodeMap.get(node);

93

const type = checker.getTypeAtLocation(tsNode);

94

const symbol = type.symbol || type.aliasSymbol;

95

96

if (isSymbolFromDefaultLibrary(program, symbol)) {

97

// It's a built-in TypeScript type

98

context.report({

99

node,

100

messageId: "builtinTypeUsage",

101

data: { typeName: symbol?.name }

102

});

103

} else {

104

// It's a user-defined type

105

context.report({

106

node,

107

messageId: "customTypeUsage",

108

data: { typeName: symbol?.name }

109

});

110

}

111

}

112

};

113

}

114

};

115

```

116

117

### Source File Analysis

118

119

Functions for analyzing the source files where symbols are defined.

120

121

```typescript { .api }

122

/**

123

* Gets the source file for a given node

124

* @deprecated Use node.getSourceFile() directly instead

125

*/

126

function getSourceFileOfNode(node: ts.Node): ts.SourceFile;

127

```

128

129

**Usage Examples:**

130

131

```typescript

132

import { getSourceFileOfNode } from "@typescript-eslint/type-utils";

133

134

// Note: This function is deprecated, prefer node.getSourceFile()

135

function analyzeNodeLocation(tsNode: ts.Node): {

136

fileName: string;

137

isDeclarationFile: boolean;

138

isExternal: boolean;

139

} {

140

// Preferred approach

141

const sourceFile = tsNode.getSourceFile();

142

143

// Deprecated approach (for reference)

144

// const sourceFile = getSourceFileOfNode(tsNode);

145

146

return {

147

fileName: sourceFile.fileName,

148

isDeclarationFile: sourceFile.isDeclarationFile,

149

isExternal: sourceFile.fileName.includes('node_modules')

150

};

151

}

152

```

153

154

## Advanced Symbol Analysis Patterns

155

156

### Declaration Context Analysis

157

158

```typescript

159

// Example: Comprehensive declaration analysis

160

import { getDeclaration, isSymbolFromDefaultLibrary } from "@typescript-eslint/type-utils";

161

162

function analyzeDeclarationContext(

163

services: ParserServicesWithTypeInformation,

164

node: TSESTree.Identifier

165

): {

166

hasDeclaration: boolean;

167

declarationKind: string | null;

168

isBuiltin: boolean;

169

sourceFile: string | null;

170

isExternal: boolean;

171

} {

172

const program = services.program;

173

const checker = program.getTypeChecker();

174

175

const declaration = getDeclaration(services, node);

176

177

if (!declaration) {

178

return {

179

hasDeclaration: false,

180

declarationKind: null,

181

isBuiltin: false,

182

sourceFile: null,

183

isExternal: false

184

};

185

}

186

187

// Get the symbol for builtin check

188

const tsNode = services.esTreeNodeToTSNodeMap.get(node);

189

const type = checker.getTypeAtLocation(tsNode);

190

const symbol = type.symbol || type.aliasSymbol;

191

192

const sourceFile = declaration.getSourceFile();

193

194

return {

195

hasDeclaration: true,

196

declarationKind: ts.SyntaxKind[declaration.kind],

197

isBuiltin: isSymbolFromDefaultLibrary(program, symbol),

198

sourceFile: sourceFile.fileName,

199

isExternal: sourceFile.fileName.includes('node_modules')

200

};

201

}

202

```

203

204

### Symbol Dependency Tracking

205

206

```typescript

207

// Example: Tracking symbol dependencies across files

208

import { getDeclaration, isSymbolFromDefaultLibrary } from "@typescript-eslint/type-utils";

209

210

interface SymbolDependency {

211

name: string;

212

sourceFile: string;

213

isBuiltin: boolean;

214

isExternal: boolean;

215

declarationKind: string;

216

}

217

218

function trackSymbolDependencies(

219

services: ParserServicesWithTypeInformation,

220

rootNode: TSESTree.Node

221

): SymbolDependency[] {

222

const dependencies: SymbolDependency[] = [];

223

const visited = new Set<string>();

224

const program = services.program;

225

const checker = program.getTypeChecker();

226

227

function visitNode(node: TSESTree.Node) {

228

if (node.type === "Identifier") {

229

const declaration = getDeclaration(services, node);

230

231

if (declaration) {

232

const sourceFile = declaration.getSourceFile();

233

const key = `${node.name}:${sourceFile.fileName}`;

234

235

if (!visited.has(key)) {

236

visited.add(key);

237

238

const tsNode = services.esTreeNodeToTSNodeMap.get(node);

239

const type = checker.getTypeAtLocation(tsNode);

240

const symbol = type.symbol || type.aliasSymbol;

241

242

dependencies.push({

243

name: node.name,

244

sourceFile: sourceFile.fileName,

245

isBuiltin: isSymbolFromDefaultLibrary(program, symbol),

246

isExternal: sourceFile.fileName.includes('node_modules'),

247

declarationKind: ts.SyntaxKind[declaration.kind]

248

});

249

}

250

}

251

}

252

253

// Recursively visit child nodes

254

// (Implementation would traverse AST)

255

}

256

257

visitNode(rootNode);

258

return dependencies;

259

}

260

```

261

262

### Library vs User Code Classification

263

264

```typescript

265

// Example: Classifying symbols by their origin

266

import { isSymbolFromDefaultLibrary, getDeclaration } from "@typescript-eslint/type-utils";

267

268

enum SymbolOrigin {

269

Builtin = "builtin",

270

External = "external",

271

UserCode = "userCode",

272

Unknown = "unknown"

273

}

274

275

function classifySymbolOrigin(

276

services: ParserServicesWithTypeInformation,

277

node: TSESTree.Identifier

278

): SymbolOrigin {

279

const program = services.program;

280

const checker = program.getTypeChecker();

281

282

// Check if it's a builtin TypeScript type

283

const tsNode = services.esTreeNodeToTSNodeMap.get(node);

284

const type = checker.getTypeAtLocation(tsNode);

285

const symbol = type.symbol || type.aliasSymbol;

286

287

if (isSymbolFromDefaultLibrary(program, symbol)) {

288

return SymbolOrigin.Builtin;

289

}

290

291

// Check declaration location

292

const declaration = getDeclaration(services, node);

293

294

if (!declaration) {

295

return SymbolOrigin.Unknown;

296

}

297

298

const sourceFile = declaration.getSourceFile();

299

const fileName = sourceFile.fileName;

300

301

if (fileName.includes('node_modules')) {

302

return SymbolOrigin.External;

303

}

304

305

return SymbolOrigin.UserCode;

306

}

307

308

// Usage in ESLint rule

309

export default {

310

create(context) {

311

const services = context.parserServices;

312

313

return {

314

Identifier(node) {

315

const origin = classifySymbolOrigin(services, node);

316

317

switch (origin) {

318

case SymbolOrigin.Builtin:

319

// Handle builtin types

320

break;

321

case SymbolOrigin.External:

322

// Handle external library symbols

323

break;

324

case SymbolOrigin.UserCode:

325

// Handle user-defined symbols

326

break;

327

case SymbolOrigin.Unknown:

328

// Handle unknown symbols

329

break;

330

}

331

}

332

};

333

}

334

};

335

```

336

337

### Declaration Relationship Analysis

338

339

```typescript

340

// Example: Analyzing relationships between declarations

341

import { getDeclaration } from "@typescript-eslint/type-utils";

342

343

interface DeclarationRelationship {

344

node: TSESTree.Identifier;

345

declaration: ts.Declaration;

346

parent: ts.Declaration | null;

347

children: ts.Declaration[];

348

siblings: ts.Declaration[];

349

}

350

351

function analyzeDeclarationRelationships(

352

services: ParserServicesWithTypeInformation,

353

identifiers: TSESTree.Identifier[]

354

): DeclarationRelationship[] {

355

const relationships: DeclarationRelationship[] = [];

356

357

identifiers.forEach(node => {

358

const declaration = getDeclaration(services, node);

359

360

if (declaration) {

361

const parent = declaration.parent;

362

const children: ts.Declaration[] = [];

363

const siblings: ts.Declaration[] = [];

364

365

// Find children (for classes, interfaces, etc.)

366

if (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration)) {

367

declaration.members?.forEach(member => {

368

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

369

children.push(member);

370

}

371

});

372

}

373

374

// Find siblings (other declarations in same scope)

375

if (parent && 'statements' in parent) {

376

(parent as any).statements?.forEach((stmt: ts.Statement) => {

377

if (stmt !== declaration && ts.isDeclaration(stmt)) {

378

siblings.push(stmt);

379

}

380

});

381

}

382

383

relationships.push({

384

node,

385

declaration,

386

parent: parent as ts.Declaration || null,

387

children,

388

siblings

389

});

390

}

391

});

392

393

return relationships;

394

}

395

```