-
Notifications
You must be signed in to change notification settings - Fork 304
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 type definitions #529
Comments
This should be easy enough by tweaking the doc build tools in place. Will have a look after the new versions are out. |
@andrewplummer Any news on this? |
@andrewplummer version 2.0.1 is out, any news on sugar.d.ts for this new version? |
Yes, now that this is released I'm going to have a look into this. It raises a question however: now that the ability to extend natives is opt-in, it seems that this means that 2 definition files are now required... 1 for non-extended use and one that will included methods that may potentially be extended. I'm thinking maybe:
Does this make sense? |
Alternately it could just be a single definition file with everything together? Would having extended-native definitions in the |
Ok, I'm having a look at this right now but there's a few roadblocks I'm hitting, and it would be nice to have some TS experts here to help out. First, is there a way for a type to explicitly refer to a global object? For example:
Here I would like |
Also, could someone check my work so far? This seems to get the job done for the main core features in 2.0.0: declare module sugarjs {
interface Sugar {
(options?: SugarOptions): Sugar;
extend(options?: SugarOptions): Sugar;
Array: SugarNamespace;
// Other namespaces listed here...
}
interface SugarOptions {
objectPrototype?: boolean;
methods?: Array<string>;
except?: Array<string>;
// TODO: Figure out global literals
namespaces?: Array<string>;
enhance?: boolean;
enhanceString?: boolean;
enhanceArray?: boolean;
}
interface SugarNamespace {
<T>(init?: T): SugarChainable<T>;
new<T> (init?: T): SugarChainable<T>;
extend(options?: SugarOptions): Sugar;
defineInstance(methods: Object): SugarNamespace;
defineInstance(name, Function): SugarNamespace;
// Other helper and method definition functions listed here...
flatten<T>(array: T[]): T[];
// Other Sugar static methods listed here...
}
interface SugarChainable<T> {
raw: T;
valueOf(): T;
flatten(limit?: number): SugarChainable<T>;
// Other sugar chainable methods listed here...
join(separator: string): SugarChainable<T>;
// Other native methods mapped to chainables listed here...
}
}
interface Array<T> {
flatten(limit?: number): T[];
// Other extended mode methods listed here...
}
declare var Sugar: sugarjs.Sugar; With this as a base it should be a matter of:
Edit: Some typos and stuff I forgot. |
Yes, it's possible, you should use |
And you have to declare |
@trikadin Cool, that seems to have worked! For the second part, I'm declaring |
In TS you have to split on class declaration into two parts: one for the static methods and properties and one for the the instance methods and properties. For example: interface ObjectConstructor { // static methods
assign<T, U>(target: T, source: U): T & U;
}
interface Object { // instance methods
hasOwnProperty(v: string): boolean;
} Thereby, you should rename your |
Ok, I see... that's interesting. Actually, though, The only instance methods I'm using (aside from on natives when in extended mode) is the Sugar chainables, but it seems that I'm already splitting them as you suggested between |
I've hit another issue, this time potentially blocking. Sugar allows user defined functions (this is a major feature of the v2.0 update) that will appear on the global object like such: Sugar.Array.defineInstance('foo', function() {});
Sugar.Array.foo(); // This function will now be available here Strangely, though, it appears that Typescript index signatures can't handle this. I've pruned it down to the following declarations file: declare module sugarjs {
interface SugarArrayConstructor {
[propName: string]: any;
}
interface Sugar {
Array: SugarArrayConstructor;
}
}
declare var Sugar: sugarjs.Sugar; Doing this will throw the error: |
Not really. That's dynamic by nature, so not typeable. |
I'm not quite sure what you mean. Index signatures are supposed to allow dynamic access to objects such as not to throw a compile error. Looking into it further, it seems that this works with brackets but not dot syntax for a property. However this isn't really a workable solution for Sugar. |
I don't know of a workaround. Property names are dynamic; so TS constrains them to [] |
Ah I see what you mean now. |
You want to create dts as a standalone module or add it to main repo? |
How can I join to development to help you with this feature? |
Good timing! I've essentially just finished with the new So the question is now what? Is it best practices to include the declarations file directly in the Sugar repo? Also, can you link me to the best guide for contributing them? Is typings the newest/best place for this? |
One thing to note is that I will need to look into the issue with being unable to define new methods. Until that is resolved, these definitions aren't exactly complete. If typescript doesn't support that (accessing arbitrary properties through the dot syntax) then new method definition cannot be supported. Also, due to typescript quirkiness with conflicting interfaces, extending |
IMHO, the best way is to include module (not extended) declaration file directly into Sugar repo, and add declaration for extended mode to typings. |
Ah I see, so split into 2 declarations? Something like:
Maybe? But why only check one into the repo? Or better question, is there a good reason to check any into the repo when they can be built easily? |
Yep)
Well, I think you right -- there's nothing bad about to add them both, and add the 'typings' field to the package.json with value './sugar.d.ts'. So, when you use Sugar in your libs (without extending) -- TS automatically finds the declaration, and you don't need to do anything more. And when you write the standalone application and you want to use extended mode -- you just add the 'sugar-extended.d.ts' into your references, just like:
Kinda long, but not the problem) |
OK that sounds pretty good. Is it customary to put them in the root directory or a subfolder? What about the file naming? |
No limitations, but usually So, imho, |
I've actually been using generics for this. Would this work: isArray<T>(instance: any): instance is Array<T>; Other generics can be derived from the ES6 typings... |
Ts reports errors for your current definitions:
Yes, it would, but you shouldn't use generics for this, because argument could be non-typed array, like Typescript built-in isArray(arg: any): arg is Array<any>; |
One more error: map<U>(map: string|sugarjs.Array.mapFn, context?: any): U[];
map<U>(map: string|sugarjs.Array.mapFn<T, U>, context?: any): U[]; |
Ok fair enough... the rest makes sense too... Will check this out |
I'll try to carry out a full inspection of all the TS definitions in the nearest future and send PR. |
Thank you! If possible can you keep track of it somewhere so I can repro the errors? |
Sorry, I don't understand... What do you want? |
Ah sorry, I just meant if you can give me some code to help test the definitions I would appreciate it :) |
Ok I re-read this and I think I finally understand what you mean. Unfortunately I think this means that I'm overusing generics in a lot of places then. For example: var squares = Array.construct(5, function(n) {
return n * n;
}); This is a common use case for this method, but in theory construct<T>(n: number, map: (i: number) => any): T[]; However should probably be this: construct(n: number, map: (i: number) => any): any[]; Would you agree? |
But actually I still find this confusing... If this is correct, then why do the native |
I'd prefer If |
I agree with @vendethiel about
For non-typed arrays you can use smth like: const bla: Array<any> = [1, '0', true, {}]; Or, if you have restricted subset of types, you may use unions: const numAndStringArr: Array<number | string> = [1, '', 'bla']; |
But, in case of |
Right, but wouldn't the generic help to facilitate that? i.e. |
if the function has the return type |
Ahh ok this is making more sense now. Also ignore my above comment, I was misunderstanding something. However it leads me to another question. For the method fromQueryString<T, U>(str: string, options?: QueryStringParseOptions): Object;
interface QueryStringParseOptions {
...
transform?: <T, U>(key: string, val: T, obj: Object) => U;
} This should probably be this: fromQueryString<T, U>(str: string, options?: QueryStringParseOptions<T, U>): Object;
interface QueryStringParseOptions<T, U> {
...
transform?: <T, U>(key: string, val: T, obj: Object) => U;
} ...right? Does that look right to you overall? |
Yes, that's right. Maybe, it have a sense to read a doc about generics) |
Oh believe me, I've been over that document many times now.... |
Ok, I fixed the issues raised in the comments:
|
Please have a look. I will also have a more thorough look at how generics are being used in each method later. However I think these should probably be ok now, as I understand that |
Another issue raised with definitions... it seems that this won't work: import SugarDate from 'sugar/date' Having a look at how lodash does it, there seems to be a main However this raises another question... lodash types are in the Looking into this raised another point. Although the user claimed it work, it seems that ES6 import syntax |
Update: It seems that declare namespace sugarjs {
interface Sugar {
Date: Date.Constructor;
}
namespace Date {
interface Constructor {
create(str?: string): Date;
}
}
}
declare module "sugar/date/create" {
var create: sugarjs.Date.create; // this is the part that won't work
export = create;
} I've tried various different approaches with the module, but it doesn't seem to be able to access |
Typescript does not pick up the sugar-extended types by default. Perhaps these could be put in a separate @jonathanhefner types package so Typescript can pick them up by default? EDIT: I've found the issue. The Object.keys() method in the sugar-extended file uses generics when it shouldn't. The current definition is this:
And it should be this:
Actually this is a separate issue. The suggestion to make a separate @types package for the sugar-extended types still stands |
I'm getting an error from webpack using the
|
I'm getting the same error from the TypeScript compiler. Any news about this? It does seem to work with the |
The file is missing an export directive. I wonder what the meaning of the end of declare module "sugar" {
const Sugar: sugarjs.Sugar;
export = Sugar;
}
declare var Sugar: sugarjs.Sugar; Maybe it's automatically translated somehow? Instead, using: export const Date: sugarjs.Date.Constructor; Seems to help. But then, I don't understand what the deal with constructors are. I replace interface Sugar {
(opts?: ExtendOptions): Sugar;
createNamespace(name: string): SugarNamespace;
extend(opts?: ExtendOptions): Sugar;
Array: ArrayConstructor;
Date: Date.Constructor;
Function: FunctionConstructor;
Number: NumberConstructor;
Object: ObjectConstructor;
RegExp: RegExpConstructor;
String: StringConstructor;
} I am quite new with Typescript, so maybe this is stupid. |
Okay, after digging a bit more in Typescript documentation, I think I was mislead. There is a simpler modification that would work: declare module "sugar-date" {
const Sugar: sugarjs.Sugar;
export = Sugar;
} |
Sugar.js is wonderful and makes writing JavaScript much more enjoyable. As I've been looking into TypeScript and some its tooling, I've been thinking Sugar.js would be an excellent complement. IntelliSense-like code completion with Sugar.js methods could be a huge productivity boost. Have there been any discussions about creating a TypeScript type definitions file for Sugar.js? (For reference, DefinitelyTyped is a repository of TypeScript type definitions for other popular JavaScript libraries.)
The text was updated successfully, but these errors were encountered: