-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Feature Request: F# style Type Provider support? #3136
Comments
👍 with the example for HTML. I don't like writing many |
The idea is definitely something we have talked about on and off over the past few years. We will need a detailed proposal of how are providers declared, implemented, loaded and discovered. |
I'm by no means any kind of expert on the TS compiler. I'm not even particularly advanced TS user right now. However, just to get the ball rolling I'll take a stab at a potential implementation for this. There's obviously a bunch of different ways this could be done, and choosing the best way will depend on a deep understanding of TypeScripts goals as a language, how modern JS runtimes optimise code, among other things. Here's a proposal for what the type provider might look like for the string formatter example:
In this implementation, a type provider is simply a function that gets annotated with @TypeProvider. Doing this means that this method must be evaluated at compile time. The type provider function may accept parameters. In this example the type provider accepts a As you can see, the TP.Function AST node constructor accepts an object with a The type provider method is evaluated at compile time for each time the type provider object is referenced with different parameters. So for example:
results in the type provider being evaluated twice, since two of these methods have the exact same parameter, they can refer to the same function. The AST node that the type provider function returns, is converted to a real function (or anything else) at compile time for any code referencing the type provider, and these AST nodes are also used to generate the JS output. So lastly, here is the JS that would be created from this code if we compiled it:
I've tried to keep to the TypeScript spirit of keeping things "just JavaScript", and making it so the JS output is still highly readable and could comfortably be used if the developer decided to drop TypeScript at some point. As you can see |
Type Providers for TypeScript would be awesome for something like Relay/GraphQL https://facebook.github.io/react/blog/2015/05/01/graphql-introduction.html |
Another approach is to have a custom |
The solution that @Arnavion proposes would also help with importing TS-foreign types in combination with webpack. A few use cases are written in #6615, and that issue is already a great change it doesn't go far enough (in my opinion). It would be great if there's a way to hook up the system and provide custom definitions for code like |
Agree that something like this would be cool. But I freestyle : https://github.com/blakeembrey/free-style (keep it all in ts for reals). My opinions on the matter : https://medium.com/@basarat/css-modules-are-not-the-solution-1235696863d6 🌹 |
@basarat While that is definitely a possible alternative, I don't think it's for the better.
|
Sorted by simply writing out the css https://github.com/blakeembrey/free-style#css-string and putting it in a style tag.
The people I speak of use ReactJs. Also they don't like the cascade + super kick ass deep in a dom tree selectors anyways.
All you needs is TypeScript + TypeScript tooling 🌹 For further discussion please mention me at the blog as I'd rather not hijack this thread. Also type providers are a cool idea and if people want them for css then 💯 x 💕 |
This would be nice for type declarations of javascript libraries that do dynamic stuff, like |
Any current discussion on this topic? JSON/REST have become the lingua franca of data communications. Having type provider supports would be an enormous boost in productivity for accessing the plethora of web api's! Is this still just waiting for specs on loading it and providing access? |
I have a partially functional prototype built on the extensibility model On Tue, Sep 20, 2016, 10:11 AM Jaremy Creechley notifications@github.com
|
I'm throwing this obvious thing in here, any future thoughts about the feature should take in account React components, e.g. think about these massive libraries which has types, but they are in React "propTypes" nonsensical format: https://github.com/callemall/material-ui/blob/next/src/IconButton/IconButton.js#L75 export default class IconButton extends Component {
static propTypes = {
children: PropTypes.node,
className: PropTypes.string,
contrast: PropTypes.bool,
disabled: PropTypes.bool,
ripple: PropTypes.bool,
theme: PropTypes.object,
};
... So type provider should be able to provide types for whole module in this example. Right now I'm wondering if I should write a |
Things like Typed CSS Modules can be done in much better fashion with this. |
While messy, a workaround is to generate interfaces outside of the compiler. I implemented the techniques from F#'s JSON type provider into a tool that generates TypeScript interfaces. Maybe it'll help some of you? |
What about something like this? Somewhere in Typescript export type TypeProvider = Function & {
TypeChecker?: Function,
IntellisenseProvider?: Function
}
import AngularTemplateType from './ng-template.tp'
export interface Component extends Directive {
template?: AngularTemplateType.Type
}
import * as Typescript from 'typescript'
export type Type = string
// ^ Fallback for old version that does not support Type Provider
// AngularTemplateType.Type will be treat as a string
const Type: Typescript.TypeProvider = function (everything) {
return Typescript.TypeFlags.String
}
Type.TypeChecker = function (everything) {
// Now impl type checker for angular template
} Or what about GraphQL import graphql from './gql'
async function getUser(id: number) {
return await graphql`
{
user(id: ${id}) {
name, age
}
}
`
}
getUser(2) // <- Type of this is Promise<{ name: any, age: any }>
import GraphQL from './gql.tp'
export default function (s: TemplateStringsArray): Promise<GraphQL> { return ... }
import * as Typescript from 'typescript'
export type Type = object
const Type: Typescript.TypeProvider = function (everything) {
return Typescript.createTypeLiteralNode(...)
}
Type.TypeChecker = function (everything) {
// Now impl validator for GraphQL
} |
|
I just wanted to voice my support and desire for this feature. I think it’s potentially incredibly valuable based on how TypeScript is often used these days for rich web apps with Webpack, REST & GraphQL, and other kinds of static but non-JS types. @weswigham what ever came of your prototype from a couple years back? Did it at least yield a proposed API that could spark further discussion? I hope the TS team seriously considers building out this potential feature, though it could also be an excellent community contribution for a bold person given a clear proposed plan. |
So, speaking from experience, while technically you can make type providers work (and I have - I did have a functional prototype based on my extension model), a better solution (from a ux perspective) is triggered codegen. Rather than writing a library that generates the types from an API or some other file and injecting them directly into a compilation or language service, it's a way better development experience to generate actual code from the API or file. When that's done, you have a source file that actually exists and can be gone to with go-to-definition and inspected for deficiencies. And I think a lot of people realize this (plus it already works today, since it doesn't need any specific hooks) - that's why there's projects for generating type declarations for things like json schemas and swagger specs. |
+1 |
if typescript has a powerful macro system:
|
Did this change? I'm looking into implementing a prototype myself and I'm evaluating what an appropriate integration would look like. |
Another use case is typesafe i18n messages ICUs. We have a distinct build step for this now, but it would be nicer if it could be hooked into the typescript project references and incremental builds mechanisms. Even using a webpack custom loader would run too late for the language service to use it. |
Type Providers could be used to support many of the same use-cases as the much requested Custom Transformers feature #14419 |
Any updates? |
This issue was opened before some things we have today existed. Nowadays, ES Module The Deno TypeScript/JavaScript runtime allows us to import using familiar For example, in Deno we can write the following: import SwaggerClient from 'https://some-swagger-api.com'
var fooClient = new SwaggerClient()
fooClient.getPeople((people) => {
people.every((person) => console.log(person.firstName + "," + person.lastName);
}); In Node.js, it is simple to make a URL module loader. This means someone can make one that loads TypeScript in Node.js (go go go!). I think this issue can be closed, and people should instead focus on building tooling around ES Module syntax. |
I'm not clear that this is a reason to close it - |
@trusktr: like @Dessix, I think you miss the purpose of F#-style Type Providers. Type Providers are not just 'yet another way to import existing code'. Instead, they enable you to programmatically derive new types (that don't exist anywhere) at design time, which the rest of your program can then type check against without ever having them declared in a source file explicitly. |
Could we get support for something like F#'s type providers in the future?
Let me present some use case scenarios for this.. Let's suppose you have a TS project trying to access a REST API, and this REST API uses Swagger or RAML for documentation. Well in this case we could have something like this;
and this could be completely type safe, as the SwaggerClient pulls down the API return types, method names (such as getPeople) and signatures at compile time and exposes them as methods to the type system. I think that's pretty huge. Such clients could be written by the community for RAML, SOAP or what have you.
another nice one:
In this example the Document type provider loads our index.html file and finds all the elements with id's and figures out what types they are, and exposes them in the type system at compile time. Again, I think that's pretty huge!
F# uses Type Providers for all kinds of things, so there's lots of ways this can get used. It's easy to see frameworks figuring out all kinds of amazing things that these could be used for. It also feels like a nice fit for TypeScript because it helps bridge the benefits on dynamic typing with the benefits of static typing.
one more tiny example:
a simple string formatter. This reads "name:%s/tid:%n" and knows that %s and %n must be replaced with a string and number respectively, so at compile time it produces a method that accepts a string parameter and a number parameter. Basically a statically typed string formatter. Just a tiny of example of handy little utilities that could be written with this feature. But the opportunity is pretty huge I think in general.
Any thoughts?
The text was updated successfully, but these errors were encountered: