-
Notifications
You must be signed in to change notification settings - Fork 195
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 typings #108
Comments
+1 |
Well, this my first try. but it isn't very good:
|
Cool! Seems like a useful addition. 😺 |
+1, would be great to have it here! |
Here is what I have come up with so far. It only allows usage of the lib in typescript. It does not provide compile time error for accessing read-only data. seamless-immutable.d.ts: declare module 'seamless-immutable' {
type Immutable = {
(obj:any, options?:any):any;
isImmutable(target:any):boolean;
ImmutableError(message:string):Error;
}
var Immutable:Immutable;
export = Immutable;
} Usage: import * as Immutable from 'seamless-immutable';
var array = Immutable(["totally", "immutable", {hammer: "Can’t Touch This"}]);
array[1] = "I'm going to mutate you!" The last line in usage will give a runtime error. It would of course be much better if it gave a compile time error. @zivni your typings look interesting but I am not sure how to use them? |
I'm looking for this as well, but my idea is a bit like the last one above I think. Use seamless-immutable as a wrapper, and then use lodash or other things to "mutate" and after that freeze again with Immutable. This way I don't need any API basically more than it's just a function that returns the same thing it took in I think... That is the theory at least. |
@jonaskello I think you should define with generic and return with it too:
So that it type checks / autocompletes the object it returns. |
Here is a version that combines the additions @Ciantic made with the methods defined by @zivni. It enables typed usage of the original type plus the extra methods that SI provides. I think what is left is to remove the mutation methods that SI bans. However I am not sure how to solve that or if it is even possible? declare module 'seamless-immutable' {
interface ImmutableCommonMethods<T>{
setIn?<U extends T>(keys: Array<string|number>, value: any): T | U;
merge?<U>(obj: U): T & U;
}
interface ImmutableObjectMethods<T> extends ImmutableCommonMethods<T> {
set?<U extends T>(key: string, value: any): U;
asMutable?(): T;
without?<U>(key: string): U;
without?<U>(keys: string[]): U;
without?<U>(...args: string[]): U;
without?<U>(keyFunction: (value: any, key: string) => boolean): U;
}
interface ImmutableArrayMethods<T> extends ImmutableCommonMethods<T> {
set?<T>(index: number, value: any): Array<T>;
asMutable?(): Array<T>;
asObject?<U>(toKeyValue: (item: T) => Array<Array<any>>): U;
flatMap?<U>(mapFunction: (item: T) => Array<U>)
}
type Immutable = {
<T>(obj: Array<T>, options?: any): Array<T> & ImmutableArrayMethods<T>;
<T>(obj: T, options?: any): T & ImmutableObjectMethods<T>;
isImmutable(target: any): boolean;
ImmutableError(message: string): Error;
}
var Immutable:Immutable;
export = Immutable;
} |
@jonaskello I couldn't get the simple d.ts working when transpiling to es6, only thing working is in this format: declare module "seamless-immutable" {
export default function <T>(obj: T, options?: any): T;
export function isImmutable(target: any): boolean;
export function ImmutableError(message: string): Error;
// ...
} Btw, I've been thinking about something awesome, if JavaScript had API like this: var frozenObject = Object.freeze({ something: [1,2,3,4,5] });
var mutatedFrozenObject = Object.mutate(frozenObject, (mutateObject) => {
mutateObject.something[1] = 99;
mutateObject.newValue = "test";
});
mutatedFrozenObject === {
something: [1, 99, 3, 4, 5],
newValue: "test"
}; The API would be probably simple enough for JavaScript engines to optimize the mutation function to work really fast, and it would allow to use all normal libraries to mutate frozen object. Best of all, it would be 100% type safe way to mutate. |
I made a small change to what @jonaskello did to this:
This way I can import using
and can create helper functions:
I only wish I could find a way to declare |
@zivni You can declare a type which is the intersection of MyType and SeamlessImmutable.ImmutableObjectMethods so you won't need to use the '&' everywhere.
|
Did you guys make any progress on this one? We've decided to use seamless-immutable @ work but we would like to have typings. |
Here are the latest typings we have, although we do not use them on our project yet: declare module 'seamless-immutable' {
interface AsMutableOptions {
deep:boolean;
}
interface ImmutableCommonMethods<T> {
setIn<U extends T>(keys:Array<string|number>, value:any):T | U;
merge<U>(obj:U):T & U;
}
export interface ImmutableObjectMethods<T> extends ImmutableCommonMethods<T> {
asMutable():T;
asMutable(asMutableOptions:AsMutableOptions):T;
set<U extends T>(key:string, value:any):U;
setIn<U extends T>(key:Array<string>, value:any):U;
update<U extends T>(key:string, updaterFunction:(value:any) => any):U;
update<U extends T>(key:string, updaterFunction:(value:any, additionalParameter1:any) => any, arg1:any):U;
update<U extends T>(key:string, updaterFunction:(value:any, additionalParameter1:any, additionalParameter2:any) => any, arg1:any, arg2:any):U;
update<U extends T>(key:string, updaterFunction:(value:any, additionalParameter1:any, additionalParameter2:any, additionalParameter3:any) => any, arg1:any, arg2:any, arg3:any):U;
update<U extends T>(key:string, updaterFunction:(value:any, additionalParameter1:any, additionalParameter2:any, additionalParameter3:any, additionalParameter4:any) => any, arg1:any, arg2:any, arg3:any, arg4:any):U;
updateIn<U extends T>(key:Array<string>, updaterFunction:(value:any) => any):U;
updateIn<U extends T>(key:Array<string>, updaterFunction:(value:any, additionalParameter1:any) => any, arg1:any):U;
updateIn<U extends T>(key:Array<string>, updaterFunction:(value:any, additionalParameter1:any, additionalParameter2:any) => any, arg1:any, arg2:any):U;
updateIn<U extends T>(key:Array<string>, updaterFunction:(value:any, additionalParameter1:any, additionalParameter2:any, additionalParameter3:any) => any, arg1:any, arg2:any, arg3:any):U;
updateIn<U extends T>(key:Array<string>, updaterFunction:(value:any, additionalParameter1:any, additionalParameter2:any, additionalParameter3:any, additionalParameter4:any) => any, arg1:any, arg2:any, arg3:any):U;
without<U>(key:string):U;
without<U>(keys:string[]):U;
without<U>(...args:string[]):U;
without<U>(keyFunction:(value:any, key:string) => boolean):U;
}
export interface ImmutableArrayMethods<T> extends ImmutableCommonMethods<T>, Array<T> {
set<T>(index:number, value:any):Array<T>;
asMutable():Array<T>;
asMutable(asMutableOptions:AsMutableOptions):Array<T>;
asObject<U>(toKeyValue:(item:T) => Array<Array<any>>):U;
flatMap<U>(mapFunction:(item:T) => Array<U>):U;
}
export function from<T>(obj: Array<T>, options?: any): Array<T> & ImmutableArrayMethods<T>;
export function from<T>(obj: T, options?: any): T & ImmutableObjectMethods<T>;
export function isImmutable(target: any): boolean;
export function ImmutableError(message: string): Error;
} If I recall correctly we had trouble with the default exported function so we skipped doing typings for that and instead went with using the from() method as it is a named export which is easier to do typings for. So usage would be something like: import * as SI from 'seamless-immutable'
const myImmutable = SI.from(myObj); As a side note I am also looking into alternate ways of achieving immutability in typescript. I have found two ways so far. First you can in ts 2.0 (or at least in 1.9 pre-release) declare your interfaces as readonly like this: interface Foo {
readonly x:string,
readonly y:number
} Second you can try to achieve immutability by tslint rules. I am doing some work on that here. |
Thanks for the update. Here is my typing after I've included missing typing that @jonaskello added:
|
Thanks a lot @jonaskello. I spent all morning battling against those typings and couldn't find a way to re-export a type corresponding to the Immutable object returned by seamless-immutable... just like you said. Your comment helped me move forward. Here's what I've ended up with:
I'll try to take some time and publish those typings as an npm package. |
The advantage of the above is that in my code I can import the same way you mentionned, but also import the Immutable type separately, which makes for a nicer TS API:
|
@zivni You may already be aware of this but if you want your typings global like that I would recommend using the
|
Nice work. @dsebastien could you add your file to tsd/npm so that anyone can use it easily? |
It may be better to include the typings into seamless-immutable package itself (https://www.typescriptlang.org/docs/handbook/typings-for-npm-packages.html), thus no external tsd/npm package will be required. |
Actually I think typings should be in their own package. That's the way the TypeScript team pushes forward now with TS 2.0+ (see here: https://blogs.msdn.microsoft.com/typescript/2016/06/15/the-future-of-declaration-files/) The reason is that people don't necessarily want to release a new version of a library because the typings are incomplete or buggy. I guess there are pros and cons to both approaches |
@dsebastien I was under the impression that the way moving forward is that the typings author should make a PR to the DefinitelyTyped repo, not produce his own npm package. Microsoft will then export DefinitelyTyped to @types npm packages automatically. Could you quote where it says they should be put in their own package? |
@dsebastien I think it is good when something forces authors to keep complete and reliable typings). |
@jonaskello might be the latest news, I don't know ^^ |
I'm experimenting with the types from @dsebastien. I added this definition:
This lets me do the following:
Which is quite handy, otherwise I would need to do some ugly type casting to get the correct type for the elements in the array. Maybe the types in It'd be awesome if someone has the time to work on a PR on https://github.com/DefinitelyTyped/DefinitelyTyped. |
I have opened this PR DefinitelyTyped/DefinitelyTyped#11717 from @dsebastien work, I did some questionable choices and I am happy to reply to any questions. I hope it will help :) |
For information the PR has been merged, feel free to open a new PR on DefinitelyTyped to improve the type definition file in case there are some quirks. |
Awesome! If @alex3165 if you'd like to open a PR to seamless-immutable to add a link to the typings in our README, I would be happy to accept it. Thanks for all the hard work on this! |
How are you supposed to use the type definition in https://github.com/alex3165/DefinitelyTyped/blob/14740e2ee4239622065cbc674d793586f5cf24b7/seamless-immutable/seamless-immutable.d.ts? I have tried these:
but neither give me an Immutable function I can use:
TypeScript says error TS2349: Cannot invoke an expression whose type lacks a call signature. |
If you use typings to manage your type declaration file :
or now with typescript 2 you can use npm to manage the types :
Then you have to import seamless-immutable like this :
|
Thanks, but now If I try and do:
I get: src/reducers/bookings/reducer.ts(10,22): error TS2349: Cannot invoke an expression whose type lacks a call signature. I thought, looking at the code at https://github.com/rtfeldman/seamless-immutable there should be an |
Try:
|
OK great - Thank you! At least I can get moving now! But why does using the typescript definition mean you can't used the documented interface? |
I have just ported the last type definition file from above to the definitelyTyped registry and cleaned it a bit so I am not too sure about this |
@alex3165 I had just installed the definitions from npm install @types/seamless-immutable and I get a different file than that hosted on DefinitelyTyped. It seems the one installed using @types... is out of date as I could not get it to work properly with an error stating the from function was not available. The new definition you have at DefinitelyTyped works because it declares the 'seamless-immutable' module correctly. Hope this helps anyone else struggling with it. Cheers |
Sine typescript 2.0 It is now possible to achieve immutability at compile-time by just using the |
@jonaskello readonly is great, but the problem is that it can't be made recursive yet, pending microsoft/TypeScript#10725 As to your library, I haven't used it yet, but it looks nice. I just wish that you could limit the linting rules to certain files: jonaskello/tslint-immutable#25 |
Commenting to follow this conversation. |
I ended up writing a new type definition file for seamless-immutable 7 that works well with TypeScript 2.4 I've had success writing product types like you see below import { ImmutableObject } from 'seamless-immutable';
type ImmutableState<T> = ImmutableObject<T> & T;
export default ((state: ImmutableState<UserState>, action: Action): ImmutableState<UserState> => {
switch(action.type) {
case 'ASSIGN_USER': {
return state.merge({number: action.number});
}
default: {
return state || initialState;
}
}
}); For anyone interested, I threw together a full example app with redux/typescript 2.4/seamless 7.1.2 |
@toranb What about |
@Connormiha I'm down to add something for it - my hacking was mostly for methods I was using (if this is something you are interested in providing type defs for I'd be willing to update it). Might ping me on that repo instead to start a thread about it |
@toranb @Connormiha where did y'all end up with the static typings? |
@lifehackett I've got a privately maintained typedef for this lib that works w/ typescript 2.7 https://github.com/toranb/seamless-immutable-tsdefs/commits/master note: I'm not actively using much typescript these days but I did manage to throw together a simple reducer using these^ typedefs and seamless immutable a while back |
Thanks for the response @toranb . I don't see a fix for the static typings in your typedef repo though. The typedefs in this lib and your repo work fine for something like I am able to extend it locally like this declare module 'seamless-immutable' {
export function set<K extends keyof T>(obj: ImmutableObject<T>, property: K, value: T[K]): ImmutableObject<T>;
export function set<TValue>(obj: ImmutableObject<T>, property: string, value: TValue): ImmutableObject<T>;
} Not sure if that is exactly the correct signature as this is my first foray into TS, but it does remove the TS errors. I'll look to contribute these back to the repo when I have some time to flush them all out, but thought I'd check that it hadn't already been done first. Thanks again |
@lifehackett fair point! I've also not tried this yet w/ typescript v2.8+ I'm happy to add you as a contributor to that one off typedefs repo if you get deep into it ;) |
Why do interface IInterface {
str: string;
}
type TImmutableType = ImmutableObject<IInterface>;
const immutableObject: TImmutableType = Immutable({
str: 'simple string'
});
const getString = (): string => immutableObject.getIn(['str']).asMutable();
^^^^^^^
TS2322: Type 'string | string[]' is not assignable to type 'string'.
Type 'string[]' is not assignable to type 'string' Is it a bag? Do we need to duplicate typings of |
I think this is a nice lib! Unfortunately my project uses typescript so I cannot use it without typings. I did some searches but came up empty so I don't think it exists? The closes I found was this question on stack overflow.
So it seems some ppl are already working on typings for this lib. I think it would be nice if we could co-ordinate the work here.
The text was updated successfully, but these errors were encountered: