Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript Roadmap: January - June 2021 #42673

Closed
DanielRosenwasser opened this issue Feb 6, 2021 · 17 comments
Closed

TypeScript Roadmap: January - June 2021 #42673

DanielRosenwasser opened this issue Feb 6, 2021 · 17 comments
Labels
Planning Iteration plans and roadmapping

Comments

@DanielRosenwasser
Copy link
Member

Roadmap Overview

This roadmap is meant to give our team and users clarity over our priorities over the next year. It's meant more as a set of guidelines than as a strict set of tasks we are bound to finish.

At a high-level, we're going to be focusing on the following 5 goals:

  • Types on every desk, in every home, for every JS developer
  • Productivity through strong tooling
  • Approachability and UX
  • Community engagement
  • Infrastructure and engineering systems

The how is broken down into the following sections:

If you've seen our last roadmap, you will notice that our goals and areas of investment haven't changed - so much so that our last roadmap sufficiently covered all of 2020. The biggest changes you might notice are specific work items and amount we'll be focusing on each area of investment.

Language design and innovation

TypeScript and the core type system

  • Enabling popular JS patterns in a type-safe way
  • Increasing expressivity
  • Proving relationships between types
  • Stricter settings
  • Implementing ECMAScript features

The goal of TypeScript's type system is to statically model patterns in JavaScript in a reasonable way while catching bugs and enforcing correctness. As more features are added to ECMAScript, and as we notice emerging patterns in the ecosystem, we have more work to do, and because the JavaScript world moves fast, so must we.

While nothing has changed here, new areas of focus might target a few core issues like:

  • More types as keys for index signatures
  • Continued investment in template string types and tuple types
  • Expanded non-strict checks (e.g. override, no property access on index signatures, unknown in try/catch)
  • Running under multiple runtimes with conflicting global declarations

Back to top

JavaScript: TypeScript beyond TypeScript

  • Making the JavaScript editing experience better
  • Smoothing the transition to TypeScript
  • Leveraging analyses outside of checkJs
  • Understanding more dynamic patterns

TypeScript isn't just for TypeScript anymore. Our userbase now includes the JavaScript ecosystem as a whole, whether they are

  • using .js/.jsx files in editors powered by TypeScript,
  • compiling purely with allowJs,
  • type-checking with checkJs (also enabled by the // @ts-check comment), or
  • transitioning to TypeScript

Whoever these users are, we believe TypeScript can serve them in some way.

We largely expect investment in the following areas:

  • editor tooling
  • leveraging TypeScript to provide stronger hints in the untyped editing experience
  • polish in the existing .d.ts file generation from .js files
  • improving parity for JSDoc mode where appropriate (e.g. supporting a broader set of tags)
  • investigating /// comments

Back to top

Committee Representation and Standards Compliance

  • Supporting modern module patterns and formats
  • Advancing committee work on decorators
  • ES/CJS module interop
  • Expression-oriented constructs

We are involved in several different committees, including TC39 and the Node modules group. We try to provide representation as

  • implementers of TypeScript, the type-checker
  • implementers of JavaScript language services & tooling
  • a voice for the users of both of the above

We're prioritizing forward compatibility with proposals/features that we've adopted early on, and we are also helping champion features which are highly-demanded from the community. To maintain focus, we will likely only be engaged with a few proposals at a time.

We hold a policy of not implementing features unless they reach stage 3 and we have high confidence in them.

Developer productivity tools and integration

Editor productivity

  • UX around refactorings/quick fixes
  • Improve experiences in partial semantic editing, such as during project load, or in-browser code exploration
  • Invest in support for the Language Server Protocol
  • Investigate opportunities to make getting started easier

Partial semantic mode has allowed editors to provide a better experience in single files while waiting for full projects to load; at the same time, we've seen that this mode can benefit in-browser scenarios as well. We'll be smoothing out the experience there as opportunities and issues arise.

We'll also be scoping out support for the language server protocol over time. Most editor support will likely continue to use TSServer in the near future, but we'll be investigating what it takes to provide an LSP server for TypeScript as well.

Back to top

Speed, scalability, and stability

  • Provide user-level tooling for profiling tsc builds
  • Address top-hitting stability issues from telemetry & crawlers
  • Investigate long-run performance wins
  • Document best practices

We've learned lots from users over the past year in investigating slow builds. We've documented some best-practices for keeping builds fast, and we've built some tooling and options like --explainFiles and --generateTrace. We'll continue improving our diagnostic tooling as we learn more.

Back to top

Education and UX

Handbook and Website

  • Investigate, experiment, and improve user flow
  • Transition docs to the new handbook
  • Better onboarding for configuration and creating projects
  • Ensure site continues to be accessible

The new website has been launched, and our handbook gathering feedback there. We'll switching over to the new handbook by default this year.

Back to top

Error and type display UX

  • "Smarter" diagnostics
  • More related error spans
  • Investigate interactive diagnostics and quick info

This area continues to receive investments, where we find heuristics to make the compiler "smarter" and provide more actionable errors.

Back to top

Community investment

downlevel-dts

downlevel-dts has been a useful tool for several partner teams. It lets library authors rewrite .d.ts files so that they can be consumed by older versions of TypeScript. For example, for Typescript 3.6, .d.ts files with get accessors in classes need to be rewritten to property declarations. This tool will need ongoing investment for each release containing new .d.ts syntax. We'd like to document this more as part of the "blessed" flow in writing libraries, and continue investment in the tool.

Back to top

DefinitelyTyped

Back to top

External contributors

  • Weekly meetings to drive down outstanding pull requests
  • Dedicated time from engineering team to assigned pull requests following release candidates

Back to top

Partner teams

We'd love to hear from your team if you use TypeScript in interesting or broadly applicable ways. This gives us insight on various things we could improve. Please give us your feedback!

Back to top

API Consumers

  • Rolling requests for API endpoints
  • Invest in support for the Language Server Protocol
  • Investigate improving rich editing experiences
    • in enhancing plugins like IntelliCode
    • in templates

Back to top

Outreach

  • Public talks
  • Meetup attendance
  • In-depth blog post content
  • Help with TSConf coordination

We want to encourage members of our team to be involved with the community, and write and talk about things that they find interesting. This keeps us close to our users and makes the project itself more approachable.

Internal engineering

Team infrastructure

  • Invest in profiling and tracing improvements
  • Invest in automated test running UX
  • Invest in various quality-of-life GitHub Actions

The idea here is really anything that improves

  • stability
  • productivity
  • ease of contribution

for development on the TypeScript project and any of our satellite projects.

We may consider building out memory profiling tools given that we need it, but few options exist for free.

Back to top

Organizational guidance

  • Internal guidance on TypeScript-first API designs
  • Providing internal partner teams with best practices for projects
  • Addressing major Microsoft-internal build regressions

We are not a company-wide build infrastructure team, but because we have the expertise and because we are involved with the JavaScript community, we're able to provide a level of guidance across Microsoft to give our peers better experiences all around. Additionally, when we hear about major build regressions on large codebases, our internal teams can provide us with their source code, allowing us to often isolate minimal repros (which is not always the case with external closed-source codebases). This work usually benefits external users in some way, whether it's because a bug fix generalizes, because we've produced better APIs, or because we've been able to extract new guidance.

Back to top

@DanielRosenwasser DanielRosenwasser added the Planning Iteration plans and roadmapping label Feb 6, 2021
@DanielRosenwasser DanielRosenwasser pinned this issue Feb 6, 2021
@awerlogus
Copy link

awerlogus commented Feb 6, 2021

I have some thoughts to say.

Smoothing the transition to TypeScript

transitioning to TypeScript

I believe that the better idea is to migrate from TypeScript to checkJs and that's why:

Code readability and aesthetics

TypeScript is a very "Horizontal" language, which means that it makes us write very (VERY) long lines of code because the types and the runtime code are declared on the same line here. The better practice is to write more code lines, but make this lines shorter. If I can write 2 lines of code with the length of 2/3 of original line, I would prefer this. And checkJs gives us this opportunity by separating the types and the runtime code. Feel the difference:

type Option<T> = T | undefined

export const map = <P, R>(func: (arg: P) => R) => (data: Option<P>): Option<R> => data !== undefined ? func(data) : undefined
/** @template T @typedef {T | undefined} Option */

/** @type {<P, R>(func: (data: P) => R) => (data: Option<P>) => Option<R>} */
export const map = func => data => data !== undefined ? func(data) : undefined

sure, we can chop that TypeScript function into a 3 lines like this:

type Option<T> = T | undefined

export const map = <P, R>(func: (arg: P) => R) => 
(data: Option<P>): Option<R> => 
data !== undefined ? func(data) : undefined

But it didn't make the code more readable at all. We can also see the main problem of such code chopping in TypeScript: some code line may be surrounded by lines that are up to 10 times longer or shorter. It typically looks like

export function notSoLongFunctionName<
T extends VeryLongGenericConstraintTypeName<AlsoLongGenericConstraintParameterTypeName>,
P
> (
parameterName: LongParameterType<T, P>,
param2: number,
parameter3: VeryLongParameterTypeName<T, P, SomeLongTypeName>
): AlwaysTheMostLongThingInTheFunctionTypeDeclarationIsItsReturnType<T> extends number 
? BecauseOfExtendsChecksAndSomeOtherThings
: never {
  const stateMap = new Map<string, VeryLongMapElementType<T, P>>()

  // other runtime code
}

It's ugly. I guess #42388 is created to partially solve this problem by determining how function generic parameters should be chopped, but we still have also function parameters and return type. This problem also persists in the runtime code too. The nice example is a creation of some Map where we pass its key and value type parameters in the same line with the variable declaration as in the code above.

No need to compile

The need to compile is not a big problem as the previous one. But anyway it may help you to start a new node.js project quicker if you don't need to setup any build tools. Just commit your code, pull it on production and it's ready to run.

checkJs problems

Of course, checkJs isn't without its problems either. The main one is that there're some features that are supported by .ts files, but not by checkJs. We can't pass generic parameters into a function, can't use as const etc. We figured out how to live with it, so I just ask you to not add any more features in the future that increase difference between typed JS and TypeScript as a language.

d.ts generation for .js files

polish in the existing .d.ts file generation from .js files

I tried this feature. The first drawback is that imports of types from other files are not preserved. Instead it produces type declaration duplicates. It may be fixed with #22160 if it will be implemented ever. The second thing is a lack of preserving empty lines between generated declarations.

Development priority

I think our new ability to work with string literals is very helpful, but we are still deadly limited in library development because of impossibility to determine that we expect not abstract number, string, object or array, but literals. Many libraries use models based on literals which are passed as parameters and then handled on both type and runtime levels. But nothing prevents you from passing just string or Record<string, any> there and breaking all type checks by it. So I believe that solving this problem is much more important than all together OOP typing problems that are currently being worked on. Issue: #41114

@glen-84
Copy link

glen-84 commented Feb 11, 2021

-TypeScript Roadmap: January - June 2021
+TypeScript Roadmap: January - December 2021
@DanielRosenwasser
Copy link
Member Author

@glen-84 well, potentially.

@MrEfrem
Copy link

MrEfrem commented Feb 17, 2021

I have some thoughts to say.

Smoothing the transition to TypeScript

transitioning to TypeScript

I believe that the better idea is to migrate from TypeScript to checkJs and that's why:

Code readability and aesthetics

TypeScript is a very "Horizontal" language, which means that it makes us write very (VERY) long lines of code because the types and the runtime code are declared on the same line here. The better practice is to write more code lines, but make this lines shorter. If I can write 2 lines of code with the length of 2/3 of original line, I would prefer this. And checkJs gives us this opportunity by separating the types and the runtime code. Feel the difference:

type Option<T> = T | undefined

export const map = <P, R>(func: (arg: P) => R) => (data: Option<P>): Option<R> => data !== undefined ? func(data) : undefined
/** @template T @typedef {T | undefined} Option */

/** @type {<P, R>(func: (data: P) => R) => (data: Option<P>) => Option<R>} */
export const map = func => data => data !== undefined ? func(data) : undefined

sure, we can chop that TypeScript function into a 3 lines like this:

type Option<T> = T | undefined

export const map = <P, R>(func: (arg: P) => R) => 
(data: Option<P>): Option<R> => 
data !== undefined ? func(data) : undefined

But it didn't make the code more readable at all. We can also see the main problem of such code chopping in TypeScript: some code line may be surrounded by lines that are up to 10 times longer or shorter. It typically looks like

export function notSoLongFunctionName<
T extends VeryLongGenericConstraintTypeName<AlsoLongGenericConstraintParameterTypeName>,
P
> (
parameterName: LongParameterType<T, P>,
param2: number,
parameter3: VeryLongParameterTypeName<T, P, SomeLongTypeName>
): AlwaysTheMostLongThingInTheFunctionTypeDeclarationIsItsReturnType<T> extends number 
? BecauseOfExtendsChecksAndSomeOtherThings
: never {
  const stateMap = new Map<string, VeryLongMapElementType<T, P>>()

  // other runtime code
}

It's ugly. I guess #42388 is created to partially solve this problem by determining how function generic parameters should be chopped, but we still have also function parameters and return type. This problem also persists in the runtime code too. The nice example is a creation of some Map where we pass its key and value type parameters in the same line with the variable declaration as in the code above.

No need to compile

The need to compile is not a big problem as the previous one. But anyway it may help you to start a new node.js project quicker if you don't need to setup any build tools. Just commit your code, pull it on production and it's ready to run.

checkJs problems

Of course, checkJs isn't without its problems either. The main one is that there're some features that are supported by .ts files, but not by checkJs. We can't pass generic parameters into a function, can't use as const etc. We figured out how to live with it, so I just ask you to not add any more features in the future that increase difference between typed JS and TypeScript as a language.

d.ts generation for .js files

polish in the existing .d.ts file generation from .js files

I tried this feature. The first drawback is that imports of types from other files are not preserved. Instead it produces type declaration duplicates. It may be fixed with #22160 if it will be implemented ever. The second thing is a lack of preserving empty lines between generated declarations.

Development priority

I think our new ability to work with string literals is very helpful, but we are still deadly limited in library development because of impossibility to determine that we expect not abstract number, string, object or array, but literals. Many libraries use models based on literals which are passed as parameters and then handled on both type and runtime levels. But nothing prevents you from passing just string or Record<string, any> there and breaking all type checks by it. So I believe that solving this problem is much more important than all together OOP typing problems that are currently being worked on. Issue: #41114

Where is a solution for using it in JSDoc https://github.com/ThomasAribart/json-schema-to-ts? It requires as const for JSON schemas to interpret string (boolean) literals as constants but not widened as strings.
I’d like to see it similar to:

/** @type {(typeof someStruct) as const} MyStruct */
@velociwabbit

This comment has been minimized.

@bodinsamuel
Copy link

Hey,
Not sure it's the best place to ping, but just wanted to highlight for future discussion: this issue.
It is probably a low hanging fruit (or not I don't know) that would drastically reduce type noise for some of us.

#22063

@eyelidlessness
Copy link

I have some thoughts to say.

Smoothing the transition to TypeScript

transitioning to TypeScript

I believe that the better idea is to migrate from TypeScript to checkJs and that's why:

Code readability and aesthetics

TypeScript is a very "Horizontal" language, which means that it makes us write very (VERY) long lines of code because the types and the runtime code are declared on the same line here. The better practice is to write more code lines, but make this lines shorter. If I can write 2 lines of code with the length of 2/3 of original line, I would prefer this. And checkJs gives us this opportunity by separating the types and the runtime code. Feel the difference:

type Option<T> = T | undefined

export const map = <P, R>(func: (arg: P) => R) => (data: Option<P>): Option<R> => data !== undefined ? func(data) : undefined

I watch line length like a hawk, and I actually find this harder to deal with when expressing types in JSDoc than in .ts(x) files. As an exercise, I’m going to reformat these types in a way similar to how I would in my editor. The narrowness/tallness will likely be exaggerated because I’m on mobile and I’m going to attempt to get it to fit on this narrow screen. But that might help illustrate how much flexibility .ts syntax has. AFAIK you can’t do this in JSDoc because types must be single-line (at least that’s what I reckon from editing in VSCode).

type Option<T> =
  | T
  | undefined

export const map = <P, R>(
  func: (arg: P) => R
) => (
  (data: Option<P>): Option<R> => (
    data !== undefined
      ? func(data)
      : undefined
  )
)

That was actually even better than I was expecting. I added parentheses around multi-line expressions to aid readability. And I didn’t need to break the ternary expression out to multiple lines to fit but I also find that improves readability.

For a bit of extra credit this also allows me to fit an explicit return type on the export and let the compiler check the returned implementation:

type Option<T> =
  | T
  | undefined

export const map = <P, R>(
  func: (arg: P) => R
): (data: Option<P>): Option<R> => (
  (data) => (
    data !== undefined
      ? func(data)
      : undefined
  )
)
@velociwabbit
Copy link

I realize i am going against the grain here but the average coder now has a minimum 1920 x 1080 screen and more often than not a 4k screen.

rather than make a case I will simply copy a gif that makes it for me.

vschess

@eyelidlessness
Copy link

I have two related questions for the TS team:

Expression-oriented constructs

This sounds intriguing but intriguingly vague! Can you elaborate (or reference standards proposals/issues tracking these)?

I recently did a “what’s happening in ESNext?” pass reading through many of the current/outstanding proposals and I was quite pleased to see a lot of them are oriented around providing richer support for functional programming patterns and more expressive expressions. Is this partly influenced by your team? (If so, thank you!)

@eyelidlessness
Copy link

I realize i am going against the grain here but the average coder now has a minimum 1920 x 1080 screen and more often than not a 4k screen.

I am a weirdo whose primary dev setup includes a 43” screen with scaling set to 4k@1x. Since I bought this display I have consistently referred to it as “comically large”, and I sincerely feel like it’s as much a monument to excess as a niche preference. All of which is setup to say: I still keep windows about the same width as they would be on my 16” MBP display, and my VSCode window showing two editor columns. Anything wider impairs my readability, as well as my ability to collaborate with other devs who actually use their laptops as portables.

This comically large screen also affords a pretty ridiculous amount of vertical screen real estate. But even for folks with more modest desktop setups, vertical scrolling is much more easily available for most people than horizontal.

Most advocates for accessible typography recommend columns of text 60-80 characters wide. I realize the tech crowd has preferences that skew from the general population, but please try to consider that horizontal sprawl and vertical density is a challenge for most people, and especially people with limited vision or cognitive impairments. Speaking (only) for myself on both: before my exercise reformatting code above I could barely make out any boundaries between types and implementation, and my ADHD kicked in and just decided it was an amorphous blob that can’t be reasoned with. Completely apart from scrolling. It was just too much information jammed together.

I think for your use case and preferences, as well as my own, it’s best to advance the capabilities of formatting/linting tools to allow each dev to read and edit in a style most comfortable to them, and to default to more commonly accessible formatting for the canonical case.

@velociwabbit
Copy link

not sure your comment addresses the core issue that i was making. Playing chess with all the pieces in view has been tested for at least 500 years as the method with the best chance of winning

the way most format code right now is at best pre-gutenberg-esque in its wisdom

@eyelidlessness
Copy link

not sure your comment addresses the core issue that i was making. Playing chess with all the pieces in view has been tested for at least 500 years as the method with the best chance of winning

the way most format code right now is at best pre-gutenberg-esque in its wisdom

I tried to address your point. I spoke to the ways people experience having pieces in view (accessible line width and how impairments affect that), as well as tooling to accommodate your needs as well as my own to ensure we both can have pieces in view.

I’m asking and inviting you to consider that other people want what you’re describing but have different needs and preferences.

@velociwabbit
Copy link

My friend, you are in the majority, and it truly flummoxes me.

And you are also the second person I have ever met who has ADHD and codes. Guess who the other one is? :)

If you tell me that you play chess the way VSCode would format it then I will say horses for courses and leave it.

If I had the memory of a chimp (which is better than ours for short-term items) then I would agree with you.

Alas, I need to see the code I work on and my eyes are horizontally aligned.

Now if I had an eye on my forehead and another one on my chin?

BTW This whole issue reminds me of the discussion about football vs soccer. Out of a roster of 44 players, only 2 actually use their feet with the ball and they do it for less than 10 seconds per game total.

Yet other than headers and off the chest, the only means of interacting with the ball in Soccer is by foot.

Go figure

:)

@eyelidlessness
Copy link

@velociwabbit I don’t feel like this is a healthy interaction for me and I’d prefer to leave it now. Thank you.

@canonic-epicure
Copy link

Is this item in the roadmap about the #35822? Or it is something different? (the #35822 is about .d.ts generation from .ts files)

We largely expect investment in the following areas:

polish in the existing .d.ts file generation from .js files
@martaver
Copy link

martaver commented Sep 7, 2021

Regarding 'Error and type display UX'...

I think a simple thing that would vastly improve this experience is touched on in another thread that I commented in:
#31940 (comment)

Namely, to simply display the highest order type alias with its generic arguments instead of attempting to display the entire type hierarchy in all its permutations.

Perhaps consider a contrived example:

In simple cases it's fine for the IDE/error to display a type as { name: string, email: string, age: number} but in terms of communicating intent to developers, it's far more useful to know that it's meant to be a Person. The fully resolved version quickly turns into unintelligible chaos as soon as any small amount of type logic is applied to it.

To a developer, it's far more useful to know that a function's arguments are meant to be a Person and be agnostic about what kinds of property being a Person entails until I really need to know about it. At which point I can jump to the type def and documentation.

Whenever type logic gets complicated enough, I'm contextually interested in the most high-order abstraction. E.g. I might need to know that this is Maybe<...> or Promise<...> or Readonly<...> because those are the constructs I have to deal with right now, at my cursor. In this case, the more terse the generic arguments the better, so that it doesn't obscure the arguments of the high-order abstraction.

In your summary you mentioned 'interactive diagnostics`... in such a system, one might 'drill down' on types and resolve them incrementally in the IDE. The first step for such an approach could be to implement this. It could be a compiler option that instructs the language server to short-circuit type resolution from aliases in prompts and errors.

Finally, if my thinking is correct, then it should also confer performance benefits during development, since complicated types may now be resolved lazily and optionally.

@Jack-Works
Copy link
Contributor

Running under multiple runtimes with conflicting global declarations

That's very useful when writing libraries targeting multiple different host environment.

For example, for DOM and Worker. It will be better to be able to use shared API in both environments and allows environment specific code by feature detection.

// Let's say this project has Dom and worker as it's environment
if (typeof importScripts === 'function') {
    // Only lib worker applies
} else {
    // Only lib dom applies
}
@RyanCavanaugh RyanCavanaugh unpinned this issue Feb 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Planning Iteration plans and roadmapping
12 participants