-
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
Ability to create a type from an inferred type and reuse it #13949
Comments
Just to understand, is the idea that I think that is an interesting idea, however, I'd like to understand how that would augment the Vue experience. While you could add an explicit type for The problem that we've run into with supporting Vue's options object is that there's circularity between the method & computed portions, as well as Vue's base instance type itself. You can see details at #12846. The motivation is that we want to say that the type of |
Hi Daniel, It could also be used much more widely - any time you write an object without first declaring an interface for it, and you want to, for example, define a function that takes an object of that type. (This is perhaps lazy programming, but also I think being able to be lazy is one of the strengths of JavaScript). I can even imagine being able to export the generated type. In terms of working with Vue, it would be acceptable to me to work this way (but not sure about others). It is often necessary to define let self=this anyway if using callbacks inside the function (Ok, you can use the arrow syntax but it still doesn't feel safe to use this inside those to me because half the time I use the function syntax out of habit and also personally I think they should behave the same as the function syntax). Also, personally I've been creating modules which export the component options object, because this gives me more flexibility in how to use it (as a local component etc) and importing the module then doesn't change global state. In this case there is no way the compiler could infer the this type, so it's necessary to specify it manually. Also, as you can see, I like to be able to split up definitions of nested objects so they don't become too nested, and the above example allows me to do that. I don't know whether you would run into any circularity problems like you have in the Vue issue you linked to, but I feel like it should be possible to implement this (although it would need to be built into the type inference system I suppose). I'm not an expert in either Vue or TypeScript, so I apologise if I've used incorrect terminology or have overlooked certain features of either of them. Also, just for the record, this suggestion has much wider scope than Vue, but that's what gave me the idea in the first place. |
After a lot of searching this is the first issue I have come across that is near what I have been wanting. My case is for react-redux. A few functions return a type that can be used in inference, or match against other types, but I can't use it myself :( This means I have to create the interface boiler that matches the function return and use that: interface ActionProps {
toggleSelect: typeof toggleSelect
}
function mapDispatchToProps(dispatch: Dispatch<any>) {
return bindActionCreators({
toggleSelect: toggleSelect
}, dispatch)
}
interface TermListProps {
title: string
filter?: Partial<Term>
}
class TermList extends React.Component<TermListProps & StateProps & ActionProps, any> In situations like this it would be nice if I could reference the return type of the function |
@ProTip Nice that someone else also likes this idea! If I understand correctly what you want, then you could rewrite your code with my proposed syntax (still not sure about the best syntax) as follows. function mapDispatchToProps(dispatch: Dispatch<any>): =ActionProps {
return bindActionCreators({
toggleSelect: toggleSelect
}, dispatch)
}
interface TermListProps {
title: string
filter?: Partial<Term>
}
class TermList extends React.Component<TermListProps & StateProps & ActionProps, any> |
Since a couple of people have replied, I thought I'd go through possible drawbacks and implementation of this idea. Possible drawbacks
Possible implementationI first thought about a "poor-man's implementation". In Visual Studio Code, you can hover over a variable (which can be a complicated object) and see its inferred type. Imagine if there was a button to generate an interface representing this inferred type (or perhaps there already is). Conceptually this is a useful starting point, especially as you can see that it would be no problem even to export the generated type from a module. However, this "poor-man's implementation" has two defects:
Now 1 could be solved by adding an extra step at the start of the compilation process that reads my suggested syntax and simply automates the "poor-man's implementation" as described above. To solve 2 using this method you would need to iterate it a few times. However, I'm sure there is a cleverer way to do it as this kind of thing must come up during the type inference, type checking or compilation process anyway. I imagine that the type inference process runs first and generates intermediate "files" with explicit types added, which is very similar to what I've just described, therefore it seems to me that the easiest way to implement it would be to integrate this syntax into the type inference system. This should also keep the increase in compile time to a minimum. Any chance someone could think seriously about this? |
I don't have a syntax preference. It seems to be that, naively, if |
@ProTip Ah, I didn't realise you could use typeof in this way in TypeScript. So it looks like this suggestion is simply an extension of that, plus maybe an alternative syntax. I think the syntax I suggested would cover the largest possible number of scenarios, but I also see how your syntax makes sense. |
Good idea. class A {
static readonly ERROR_EXAMPLE = {
110: 'error msg',
111: 'error msg',
112: 'error msg',
113: 'error msg',
121: 'error msg',
122: 'error msg',
123: 'error msg',
124: 'error msg',
...
// too many items
...
}
} In this case, I want interface X {
readonly 110: string;
readonly 111: string;
...
} Why not use Assumption: class A {
static readonly ERROR_EXAMPLE: Readonly<TypeInferred> = {
110: 'error msg',
111: 'error msg',
112: 'error msg',
113: 'error msg',
121: 'error msg',
122: 'error msg',
123: 'error msg',
124: 'error msg',
...
// too many items
...
}
}
// export its type
export <TypeSpecified>A.ERROR_EXAMPLE;
export <TypeInferred>A.ERROR_EXAMPLE; It sounds nice. |
function freeze<T>(obj: T): Readonly<T>;
const d = freeze({val: 1}); // d's type equal `interface D { readonly val: number };` But we cannot use d's type. type D = freeze({val: 1}); It looks fine if above code works, but actually it's not. |
The broad use cases here are now capturable with |
As this comes up as one of the first things in google when looking for such questions asked... If you want to create/extract type from inferred type of some known variable, here is the simple example of how you can do that without any fancy syntax or generics: const person = {
name: 'john',
surname: 'doe',
age: 33,
employed: true,
}
type PersonType = typeof person // getting person's inferred type
If you need to pull out only the return type from a function that has a known/inferred return type, previous answer using const personCreator = () => ({
name: 'john',
age: 33,
employed: true,
})
type CreatorFunctionType = typeof personCreator // getting function's inferred type
type CreatorFunctionReturnType = ReturnType<CreatorFunctionType> |
First of all, apologies if this is already possible or has already been suggested.
I'm a bit lazy when it comes to front-end development, so the type inference provided by TypeScript is very useful to avoid having to define interfaces etc.
However, sometimes I know that an object is of the same type as (or an extension of) another object but there's no way for the compiler to know. Therefore it would be useful for me to be able to save an inferred type for later reuse.
For example, I use VueJS components. To do this I need to provide a component options object which contains a methods object and a data function which returns the data. For example
The self in the above code has the any type, but I as the developer know that the contents of methods and the result of create data will will available on this type. So it would be great it I could do something like this.
I'm not sure about the syntax but the =MyType is meant to mean that instead of requiring the object to be an instance of that type, it defines a new type MyType equal to the inferred type of the object. (The syntax should also work if I'd used let, as in, let methods: =MyMethods = {method1, method2}, instead of the angle brackets). Then I would have intellisense and type checking.
Apologies again if this is already possible or has already been suggested. I just thought I'd suggest it in case it was a good idea.
The text was updated successfully, but these errors were encountered: