2

I have a TypeScript project which is compiled with "target": "es5". I use core-js's Set so I have core-js and @types/core-js installed in my project. However, since the core-js d.ts includes a global declaration of Set and Map (and other ES6 features), the TypeScript compiler allows me use them, which obviously won't work in an old browser.

I can't exclude the core.d.ts from build because I obviously need it for the interfaces.

Is there a way for the compiler to prevent me from using ES6 features and still use core-js and its corresponding type definitions?

3
  • What interfaces do you need from it? If you do not want to use es6 features then you should not need the types that correspond to those features. Commented Feb 5, 2017 at 11:52
  • I want to use Set. But I don't want to use core-js as a global replacement but rather as a library. So I have import * as CoreSet from "core-js/library/fn/set"; in the file which needs it. So I can do new CoreSet<number>(). But the problem is that I can also do new Set<number>() and it compiles perfectly, and then fails in the browser. Commented Feb 5, 2017 at 11:56
  • I see. Since core-js is a polyfill its declarations are designed to modify the global scope. I would recommend that you find or create your own declaration of the set interface, it is fairly simple, and definitely remove the @types/core-js package as it will wreak havoc on your namespace Commented Feb 5, 2017 at 12:05

1 Answer 1

2

Since core-js is a polyfill its declarations are designed to modify the global scope. I would recommend that you find or create your own declaration of the set interface, it is fairly simple. Definitely remove the @types/core-js package.

A declaration that you could use would look like

declare module "core-js/library/fn/set" {
  class Set { ... }
  export = Set;
}

Note that this is an ambient external module declaration with a name that matches the import path of the actual JavaScript file as resolved by your loader or by node's require function.

Ambient external module declarations should be avoided where possible, as they all contribute to a global namespace of ambient external modules, but in this case it is difficult to avoid.

One way you can avoid it is by using the paths configuration in your tsconfig.json.

path-to-non-ambient-declaration.ts

class Set { ... }
export = Set;

tsconfig.json

{
  "compilerOptions": {
     "baseUrl": "",
     "paths": {
       "core-js/library/fn/set": [
         "path-to-non-ambient-declaration"
        ]
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the detailed answer! I'm having trouble with the constructor though. I defined class Set<T> { new (): Set<T>; new (values: ArrayLike<T> | Set<T>): Set<T>;... But when I try to call new Set<string>(someOtherSet) I get an error saying "expected 0 parameters but invoke with 1"
Use the constructor keyword to declare the constructor and place the type argument on the class itself or for an alternate approach using a pair of interfaces see lib.es2015.d.ts in the TypeScript install directory, it contains a declaration for Set and SetConstructor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.