Skip to content

Some JS API types don't match their runtime valuesΒ #64864

Open

Description

@auvred

πŸ”Ž Search Terms

types, JS API

πŸ•— Version & Regression Information

Checked on the latest main (5237fd4)

⏯ Playground Link

No response

πŸ’» Code

// generated.ts
import { API, SignatureKind } from '@typescript/typescript/sync';
import { isArrowFunction, SyntaxKind } from '@typescript/typescript/ast';
import { createFileSystem } from '@typescript/typescript/fs';

const file = '/repro.ts';
const api = new API();
const snapshot = api.createSnapshot({
    fileSystem: createFileSystem([[file, `
        declare function f(): number;
    `]]),
    createPrograms: [{ rootFiles: [file], compilerOptions: { noLib: true } }],
});
const program = snapshot.operation.createdPrograms[0]!;
const source = program.getSourceFile(file)!;
const declaration = source.statements[0]!;
const checker = program.getProject().checker;
const signature = checker.getSignaturesOfType(checker.getTypeAtLocation(declaration), SignatureKind.Call)[0]!;
const arrow = checker.signatureToSignatureDeclaration(signature, SyntaxKind.ArrowFunction);
if (arrow && isArrowFunction(arrow)) {
    console.log('ArrowFunction.equalsGreaterThanToken', arrow.equalsGreaterThanToken);
    //                                                         ^? (property) ArrowFunction.equalsGreaterThanToken: EqualsGreaterThanToken
}
// factory.ts
import { SyntaxKind, type Node } from '@typescript/typescript/ast';
import * as factory from '@typescript/typescript/ast/factory';

const id = factory.createIdentifier('x');
const type = factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
const exportDeclaration = factory.createExportDeclaration();

console.log({
    'Block.multiLine': factory.createBlock([]).multiLine,
    'ArrayLiteralExpression.multiLine': factory.createArrayLiteralExpression([]).multiLine,
    'ObjectLiteralExpression.multiLine': factory.createObjectLiteralExpression([]).multiLine,
    'ImportAttributes.multiLine': factory.createImportAttributes(SyntaxKind.WithKeyword, []).multiLine,
    'ExportDeclaration.isTypeOnly': exportDeclaration.isTypeOnly,
    'SyntheticExpression.isSpread': factory.createSyntheticExpression(type).isSpread,
    'JsxText.containsOnlyTriviaWhiteSpaces': factory.createJsxText('text').containsOnlyTriviaWhiteSpaces,
    'JSDocTypeLiteral.isArrayType': factory.createJSDocTypeLiteral().isArrayType,
    'ModifiersBase.modifierFlags': exportDeclaration.modifierFlags,
    'NodeArray.transformFlags': factory.createNodeArray([id]).transformFlags,
    'Node.parent': id.parent,
} satisfies Record<string, boolean | number | Node>);
// parser.ts
import {API} from '@typescript/typescript/sync';
import {
  type Node, isDefaultClause, isExportAssignment, isPropertyAssignment,
  isShorthandPropertyAssignment, isPropertySignatureDeclaration, isIndexSignatureDeclaration,
  isTaggedTemplateExpression, isJSDocSeeTag, isJSDocTemplateTag,
} from '@typescript/typescript/ast';

function walk(node: Node): void {
  if (isDefaultClause(node)) console.log('DefaultClause.expression', node.expression);
  if (isExportAssignment(node)) console.log('ExportAssignment.type', node.type);
  if (isPropertyAssignment(node)) console.log('PropertyAssignment.type', node.type);
  if (isShorthandPropertyAssignment(node)) console.log('ShorthandPropertyAssignment.type', node.type);
  if (isPropertySignatureDeclaration(node)) {
    console.log('PropertySignatureDeclaration.type', node.type);
    console.log('PropertySignatureDeclaration.initializer', node.initializer);
  }
  if (isIndexSignatureDeclaration(node)) console.log('IndexSignatureDeclaration.type', node.type);
  if (isTaggedTemplateExpression(node)) console.log('TaggedTemplateExpression.questionDotToken', node.questionDotToken);
  if (isJSDocSeeTag(node)) console.log('JSDocSeeTag.nameExpression', node.nameExpression);
  if (isJSDocTemplateTag(node)) console.log('JSDocTemplateTag.constraint', node.constraint);
  node.forEachChild(walk);
  node.jsDoc?.forEach(walk);
}

const api = new API();
walk(api.createSourceFile('/repro.ts', `
  switch (x) { default: break; }
  export default 0;
  const object = {x, y: 1};
  interface I { p; [key: string]; }
  tag\`text\`;
`).sourceFile);
walk(api.createSourceFile('/repro.js', `
  /** @see */ function a() {}
  /** @template T */ function b() {}
`).sourceFile);

and then run

node generated.ts
node factory.ts
node parser.ts

πŸ™ Actual behavior

> node generated.ts 
ArrowFunction.equalsGreaterThanToken undefined

> node factory.ts 
{
  'Block.multiLine': undefined,
  'ArrayLiteralExpression.multiLine': undefined,
  'ObjectLiteralExpression.multiLine': undefined,
  'ImportAttributes.multiLine': undefined,
  'ExportDeclaration.isTypeOnly': undefined,
  'SyntheticExpression.isSpread': undefined,
  'JsxText.containsOnlyTriviaWhiteSpaces': undefined,
  'JSDocTypeLiteral.isArrayType': undefined,
  'ModifiersBase.modifierFlags': undefined,
  'NodeArray.transformFlags': undefined,
  'Node.parent': undefined
}

> node parser.ts 
DefaultClause.expression undefined
ExportAssignment.type undefined
ShorthandPropertyAssignment.type undefined
PropertyAssignment.type undefined
PropertySignatureDeclaration.type undefined
PropertySignatureDeclaration.initializer undefined
IndexSignatureDeclaration.type undefined
TaggedTemplateExpression.questionDotToken undefined
JSDocSeeTag.nameExpression undefined
JSDocTemplateTag.constraint undefined

All these properties have non-nullish declared types, however in runtime they're all undefined.

πŸ™‚ Expected behavior

Runtime values of these properties should match their declared types.

Additional information about the issue

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions