Skip to content

JavaScript types in TypeScript #4790

Closed
Closed
@billti

Description

@billti

JavaScript types in TypeScript

This write-up outlines considerations for potential integration of JavaScript and TypeScript at the type system level. (See parent issue #4789 for an overview)

Basic inference as it works today

Several constructs in JavaScript will be recognized and typed using TypeScript inference today, for example:

var x = 10;            // <- number
var y = [true, false]; // <- Array<boolean>
var z = {              // <- {a: string; b: Date}
  a: "test", 
  b: new Date()
}
function f(){          // <- { (): number; }
  return 3.14;
}

There are several limitations however that the TypeScript type annotations were designed to support. For example:

function foo(a, b){
  return a + b;
}

Here there is no way to infer the types of 'a' or 'b' (and thus also the return type), and no way in the JavaScript syntax to specify the parameter types. For simple cases, this case be accurately and equivelently modeled using JsDoc annotations. For example:

/**
 * @param {string} a
 * @param {number} b
 * @returns {string}
 */
function foo(a, b){
  return a + b;
}

Which is identical in meaning to the following TypeScript:

function foo(a: string, b: number): string {
  return a + b;
}

(Note that in this simple case the return type is not necessary, and could have been inferred once the paramater types were known).

Below shows some more JsDoc annotations that model similar TypeScript constructs closely, such as union types, object literal types, optional types, "any" types, generic types, rest args, referencing declared types, etc...

/** This function demonstrates union types, object literal types, "any" types, and optional params
 * @param {(number|string)} a - First param is string or number
 * @param {{name: string, age: number}} b - Second param is an object type
 * @param {*} [c] - Third param is any type, and optional
 * @return {Object}
 */
function myFunc(a,b,c){
    if (c && b.age > 42) return {};
}


/** This function demonstrates generic types and rest args
 * @template T
 * @param {T} x - Some input type
 * @param {...number} y - A list of numbers 
 * @return {T} - Return type will be the type of the first parameter
 */
function func2(x, y){
    return x;
}
func2("test", 1, 2, 3).charAt(2);


/** @type {Document} */
var someDoc;   // Equivalent to "var someDoc: Document" in TypeScript

Consuming and providing types

Similar to the way TypeScript works today, files are included in a project "context", and the values and types in that context are visible across files (according to the rules on scope and visibility). For example, the interface foo may be declared in file foo.d.ts, which may be included in the project context via the command-line, tsconfig.json, or a /// <reference ..> line at the start of the file. JsDoc annotations would then be able to reference the type foo in the JavaScript files.

Similarly, the JavaScript file may declare a value test with a type of {name: string, age: number}, and the identifier test would then be available to TypeScript files in the same context with the type given.

Beyond the simple scenarios for values and types given above, this also extends to the module system, where code authored in JavaScript may import a module written in TypeScript, and vice-versa.

TODOs and open questions:

  • Point to the current prototype and outline the JsDoc tags supported in it
  • Reference the analysis data on the JsDoc types seen most commonly in code analyzed
  • Determine the value or requirements for accurately modeling existing system, e.g.
    • Do we need/want to be compatible with Closure Compiler?
    • Do we want JavaScript type declarations to be equivalent in expressiveness to TypeScript?
  • Outline using common JavaScript class patterns (using both ES6 classes and adorning the 'prototype' property of a constructor function)
  • Decribe declaring interfaces (using @typedef)
  • Outline declaration and consumption of module types in JavaScript (CommonJS, AMD, and ES6)
  • Verify and describe usage of newer ES6 features such as generators, spread/rest args, optional/default params/members, etc...
  • Outline patterns the TypeScript engine doesn't support today for type inference from JavaScript code (e.g. mixin patterns, expando objects, code flow sensitive types, dynamic 'this' type, etc...)
  • Discuss integration concerns, e.g.
    • How do JavaScript types appear in TypeScript? Are they strongly typed only in explicitly annotated?
    • How do types flow between them (including round-tripping)?
    • How to allow for future iteration in a backwards compatible way (e.g. if inference or type flow changes)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    FixedA PR has been merged for this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions