Definitelytyped: jasmine typing is wrong since last update

Created on 12 Feb 2017  Â·  32Comments  Â·  Source: DefinitelyTyped/DefinitelyTyped

  • [X] I tried using the @types/xxxx package and had problems.
[12:09:07]  typescript: node_modules/@types/jasmine/index.d.ts, line: 39 
[12:09:07]  typescript: node_modules/@types/jasmine/index.d.ts, line: 39 
[12:09:07]  typescript: node_modules/@types/jasmine/index.d.ts, line: 39 
[12:09:07]  ngc failed: Failed to transpile TypeScript 
[12:09:07]  ionic-app-script task: "build" 
[12:09:07]  Error: Failed to transpile TypeScript 
Error: Failed to transpile TypeScript
    at /bitrise/src/node_modules/@ionic/app-scripts/dist/aot/aot-compiler.js:70:47

      L38:      var clock: () => Clock;
      L40:      function any(aclass: any): Any;

            A parameter initializer is only allowed in a function or constructor implementation. 

      L38:      var clock: () => Clock;
      L40:      function any(aclass: any): Any;

            Cannot find name 'keyof'. 

      L38:      var clock: () => Clock;
      L40:      function any(aclass: any): Any;


npm ERR! Linux 4.4.0-57-generic
npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "run" "ionic:build" "--" "--release" "--prod"
npm ERR! node v7.5.0
npm ERR! npm  v4.1.2
npm ERR! code ELIFECYCLE
npm ERR! [email protected] ionic:build: `ionic-app-scripts build "--release" "--prod"`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] ionic:build script 'ionic-app-scripts build "--release" "--prod"'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the example package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     ionic-app-scripts build "--release" "--prod"
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs example
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls example
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /bitrise/src/npm-debug.log

Don't know if there was a merge on last update which makes the jasmine typings broken or something else which goes wrong 👎

Most helpful comment

@Bubelbub, I think that the correct solution here is to update your TypeScript version to the latest minor release of 2.x branch (which is 2.1.6 at the moment). I noticed that ionic-app-scripts are requiring 2.0.x, so I created a pull request here: https://github.com/driftyco/ionic-app-scripts/pull/737

All 32 comments

@Bubelbub , it seems like you are using TypeScript below 2.1 under the hood:

https://github.com/driftyco/ionic-app-scripts/blob/master/package.json#L98

However, it raises the following question: why were you able to update to typings of an incompatible version? As you could notice they are marked for TypeScript 2.1 and higher. This might be a bug or a misconfiguration.

I'll keep you updated.

Also, as a temporary workaround you could change the version to 2.5.41.

Thats what I did currently but anyway its a bug then 😥

Am 12.02.2017 um 16:26 schrieb Yaroslav Serhieiev notifications@github.com:

Also, as a workaround you could change the version to 2.5.41.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

Not sure right now if this is a bug... I'm examining this thread currently, it pours some light : https://github.com/Microsoft/types-publisher/issues/214

@Bubelbub, I think that the correct solution here is to update your TypeScript version to the latest minor release of 2.x branch (which is 2.1.6 at the moment). I noticed that ionic-app-scripts are requiring 2.0.x, so I created a pull request here: https://github.com/driftyco/ionic-app-scripts/pull/737

I get these same issues for Angular. Until their 4.x release, they're sticking with typescript@~2.0.10. If this is introducing changes that require Typescript 2.1.x, perhaps there should be a version bump in the minor instead of the patch? In the meantime, yes, downgrading to 2.5.41 fixes the errors.

Just ran into this today. The actual correct solution would have been to bump the minor version for this package, instead of suggesting everyone else either downgrade @type/jasmin or upgrade tsc. Semantic versioning 101 people.

@wheelerlaw , I'm afraid we cannot bump the minor version just out of the blue, because of https://github.com/DefinitelyTyped/DefinitelyTyped/issues/13225 guidelines. If I get it right, the idea is to maintain consistency at least between major and minor digits of the library version, so in my case (adding a TS2.1 feature to the jasmine definition) I could only increment the last digit, unfortunately. See the quote:

The last digit reflects updates to the package structure (IE: maybe someone made a more accurate type definition to the 4.14 changes).

I agree that the official recommendation to add magic comments like // TypeScript Version: 2.1 does not seem to be complete in addressing the versioning issues.

Also, I noticed another pull request that aims to add a safeguard for the further npm updates of @types/jasmine: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/14621 .

@Le0Michine , could you elaborate how does the added package.json affect the installation/update process of @types/jasmine? Is it going to help right now or just potentially in the future?

@noomorph will check

@noomorph as I see @types/jasmine has dependency >= 2.1.4 for Typescript in it's own package.json:
image

it was the purpose of the mentioned PR.

If you try to install new @types/jasmine version in environment with TS < 2.1.4 it will install newer TS version into it's own @types/jasmine/node_modules folder without any warnings in command line:
image

if TS >= 2.1.4 is already installed then it won't be installed additionally with @types/jasmine

npm version on my laptop is 3.10.3
experiments were performed under macOS Sierra 10.12.3

Is it what you wanted to know? Or probably you asked about some other cases?

@noomorph If there is shoud be such an error in console:
image

we need to specify typescript>=2.1.4 in peerDependencies instead of dependencies in the package.json

@noomorph just created a PR #14788 for it, I think it should resolve the issue, if you agree that peerDependency more appropriate place for TS you can merge it.

@Le0Michine , thanks for your time and investigation. The thing is that I just overlooked your recent PR adding a package.json but it seemed potentially interesting, and since you did not elaborate inside the PR on which effect it is supposed to have, I decided to clarify it a bit.

To be honest, initially, I thought that this prevents npm update from updating to a version of @types/jasmine which requires a higher version of tsc than currently available in a project. But if I understand correctly, with peerDependencies we're going to receive something similar — although _it won't be smart enough_ to choose the latest compatible version, at least will tell us that the latest version of @types/jasmine is potentially not compatible with ts-2.0. Did I understand right?

@noomorph unfortunately yes, if you run npm update when @types/jasmine have unfixed version in config (e.g. using ^version or >=version etc.) it will be updated up to most recent version which is allowed by config.

In case if TS is specified in peerDependencies you will get a warning about UNMET PEER DEPENDENCY ... so you know that something possibly may not work.

In case if TS is in dependencies it will be silently installed for the package but not for project so build will fail if project uses older version of TS.

The only difference I found is warning for peerDependencies. Sometimes it can save a bit time for investigation.

PS. I created a small package to play with, it will be available for some days so you can also perform such experiment.
Test package has two versions:
[email protected] without any dependencies
[email protected] with [email protected] as a peerDependency

just create a dumb project with npm init and install [email protected] and [email protected], fix version of typescript and try run npm update

@noomorph I didn't find any way to make npm update safer. It seems the best solution is to increase first digit of version, so ^1.2.1 won't be updated up to 2.0.0 automatically.

this is the same problem as discussed in this merge request https://github.com/DefinitelyTyped/DefinitelyTyped/pull/13994

TLDR;

Typings cannot follow SemVer as they need to stay the same Major and Minor version as the package they are for.
Solution is never install typings with weak versioning (^ or ~). Always add them with a fixed version so you will never automatically install a version that uses TS feature your current setup does not support

@lukas-zech-software , yeah, I completely agree about that and I also wrote a similar thing above.

By the way, what do you think about this approach? https://github.com/DefinitelyTyped/DefinitelyTyped/pull/14788

Looks like a decent way to alarm you that something in types is likely to break.

@noomorph :+1: looks reasonable to me, at least this will give you a warning.

Although I think, it should become best practice be to add typings only with fixed version as the SemVer operators don't make sense on something that doesn't follow SemVer.

For example all automated tests will still break as they ignore the peerDependency warning

@lukas-zech-software you are right, I just forgot that it is not a standalone package

I have faced with the following problem:

describe('test', () => {
  interface Test {
    test1(): void;
    test2(): void;
  }

  it('should test', () => {
    const a: Test = {
      test1: () => {},
      test2: () => {},
    };

    expect(a).toEqual({
      test1: jasmine.any(Function), // here the error occurs
      test2: jasmine.any(Function),
    });
  });
});

It works with bare jasmine, but causes following error withts`:

Argument of type '{ test1: Any; test2: Any; }' is not assignable to parameter of type 'Expected<Test>'.
Type '{ test1: Any; test2: Any; }' is not assignable to type 'ObjectContaining<Test>'.
Property 'jasmineMatches' is missing in type '{ test1: Any; test2: Any; }'.

Info:
TSC: 2.3.2
types/jasmine: 2.5.47

@lodin
The error occurs because the object to provide in the toEqual function is not compatible with the interface Test.

You can see that better if you split the code like so

describe('test', () => {
  interface Test {
    test1(): void;
    test2(): void;
  }

  it('should test', () => {
    const a: Test = {
      test1: () => {},
      test2: () => {},
    };

    const expected:Test = { // here the error occurs
      test1: jasmine.any(Function), 
      test2: jasmine.any(Function),
    };

    expect(a).toEqual(expected);
  });
});

jasmine.any(Function) returns an object of type Any (not the TS type any) and this type is not a function, therefore it is not compatible with () => {}

a possible fix for could be to extend the Any interface with a function signature like so

interface Any {
        ():any; // now Any is also a function
        new (expectedClass: any): any;

        jasmineMatches(other: any): boolean;
        jasmineToString(): string;
}

this needs to be tested if there are any complications but seems like a solution to your problem

@Lodin I added these changes to my latest PR #16408

As soon as that change is merged your use case should compile correctly.

Until then you can simply cast the return value of jasmine.any to any like so

interface Test {
            fn1(): void;
            fn2(param1: number): number;
        }

        const a: Test = {
            fn1: () => { },
            fn2: (param1: number) => { return param1; },
        };

        const expected: Test = {
            fn1: <any>jasmine.any(Function),
            fn2: <any>jasmine.any(Function),
        };

        expect(a).toEqual(expected);

With the new TypeScript update 2.4.1 I get the following error:

expect(totalPrice).toEqual(jasmine.objectContaining({
    price: 1337
}));
Argument of type 'ObjectContaining<{ price: number; }>' is not assignable to parameter of type 'Expected<TotalPrice>'.
  Type 'ObjectContaining<{ price: number; }>' is not assignable to type 'ObjectContaining<TotalPrice>'.
    Type '{ price: number; }' is not assignable to type 'TotalPrice'.
      Property 'productsPrice' is missing in type '{ price: number; }'.

Edit: My bad, my mock data was invalid to begin with.

@tuhoojabotti
Could you please share the interface/type TotalPrice?

Assuming it has the properties price and totalPrice this works fine for me

interface TotalPrice {
  price: number,
  productsPrice: number,
}
const totalPrice: TotalPrice = {
  price:         1,
  productsPrice: 1,
};

expect(totalPrice).toEqual(jasmine.objectContaining({
  price: 1337
}));

@lukas-zech-software Sorry, my bad. I had my interface defined as strings (because we use BigNumber.js) and the test was using numbers as mock data. It's nice that the new version of TypeScript catches this. Although I think the error message could be clearer.

Having run into a similar issue using the new generically-typed objectContaining method, I had a look at the signature, and the issue is that the built-in Partial<T> is too constraining for this method.

What you really need to do is create a new type alias, such as:

type PartialObjectContaining<T> = {
    [K in keyof T]?: T[K] | ObjectContaining<T[K]> | ArrayContaining | Any;
};

Although even this is not enough, because it doesn't work correctly for array properties.

Consider this example:

interface Item {
   description: string;
   address: string[];
}

it('should compile with object containing', () => {
    let actual: Item = { ... };
    expect(actual).toEqual(jasmine.objectContaining({
        description: jasmine.anything(), // Fails currently because `Any` is not assignable to `string`
        address: jasmine.arrayContaining(['an address']) // Fails because `ArrayContaining` is not an array
    });
});

@schmuli
Your problem comes more from the signature of jasmine.Any and jasmine.ArrayContaining

jasmine.Any is not fully compatible with any as no custom can be truly compatible with a primitive type like any
This could be resolved by adding | any to all methods returning Any

declare namespace jasmine {
  function anything(): Any | any;
}

The typing of jasmine.ArrayContaining could be adapted to

declare namespace jasmine {
   interface ArrayContaining extends Array<any> {
        ...
    }
}

Which would make it compatible to any Array.

I am unsure about the implications of these changes, as I can't test them thoroughly at the moment.
Maybe you can try them and see if they fix your problems

I'll have another look at ArrayContaining since, after adding the PartialObjectContaining type from my comment, that is the only thing that was still not working. I didn't want to provide only a partial solution, and I was hoping maybe somebody else has run into this as well.

I'm seeing this with only objectContaining and TypeScript 2.6's strictFunctionTypes/strict option. Is this the same issue?

const x: { id: number, text: string, foo: string } = { id: 123, text: 'abc', foo: 'foo' }
expect(x).toEqual(jasmine.objectContaining({ id: 1, text: 'alpha' }))

// => [ts] Argument of type 'ObjectContaining<{ id: number; text: string; }>' is not assignable to parameter of type 'Expected<{ id: number; text: string; foo: "bar"; }>'.

Doesn't look like all of the jasmine typings authors got mentioned on this issue (as suggested by the issue template), so: @borisyankov @theodorejb @davidparsson @gmoothart @lukas-zech-software

@wilg Your example code seems incomplete.

The error states that the property foo as the string literal bar as type which does not match with the example you posted where foo is of type string?

Apart from that I can recreate your issue with TS 2.6 but I am not sure how to solve this. I haven't worked with strictFunctionTypes yet but it seems to contradict with the type of Expected<T> as this can be a multitude of types.

jasmine is very dynamic with what its functions return ...

Probably we need to split type Expected<T> = T | ObjectContaining<T> | Any | Spy; in four different types an use them where appropriate.

Just a guess though.

The only workaround I can offer for now is to tell the compiler explicitly which of the return types you expect like so

interface foo { id: number, text: string, foo: string }

const x: foo = { id: 123, text: 'abc', foo: 'foo' }
expect(x).toEqual(jasmine.objectContaining({ id: 1, text: 'alpha' } as Partial<foo>))

Anyway I would suggest you open a own issue for this as this thread now already contains three different problems

Was this page helpful?
0 / 5 - 0 ratings