kimamula / ts-transformer-keys

A TypeScript custom transformer which enables to obtain keys of given type
MIT License
772 stars 84 forks source link

ts_transformer_keys_1.keys is not a function #4

Open llanginger opened 7 years ago

llanginger commented 7 years ago

Hi there!

This package sounds like the ideal solution to a problem I have but I am struggling to get past the following error: "TypeError: ts_transformer_keys_1.keys is not a function" and I am not sure how to tell if this is an error on my part or if there is something out of my control that is not working.

I have tried compiling the following file with typescript 2.4.0 and running in the browser with no other packages:

import { keys } from "ts-transformer-keys";

interface Props {
    id: string;
    name: string;
    age: number;
}
const keysOfProps = keys<Props>();

console.log(keysOfProps); 

I have also tried using ts-node and executing the same file from the command line, though here in particular I am unsure to what extend ts-node is a bottleneck.

I hope I'm missing something super simple!

Thanks in advance for any thoughts in any direction!

llanginger commented 7 years ago

I think I misunderstood something fundamental about how one is meant to use this! Will reopen if after more thorough testing I still can't get anywhere!

hhshan commented 6 years ago

@llanginger were you able to come up with a workaround. cause I too ran into the same issue trying to use this package.

kimamula commented 6 years ago

The error TypeError: ts_transformer_keys_1.keys is not a function means that you have failed to get the custom transformer working during compilation.

Could you show me how you are using the custom transformer to compile your TypeScript codes?

hhshan commented 6 years ago

Hi @kimamula I got around the issue.. was a problem with how i used the transformer. thanks for the library.. helps to solve a major issue i was facing with

martnst commented 6 years ago

I get the same TypeError: ts_transformer_keys_1.keys is not a function by simply adding it via yarn add -D ts-transformer-keys and then trying to use it as of the example. It seems there is some step missing in the docs?

kimamula commented 6 years ago

@martnst Sorry for the late response. If you are using Windows, the issue is probably fixed by this commit. Please try v0.3.1.

pamls commented 6 years ago

@kimamula unfortunately, v0.3.1 does not work on Windows.

martnst commented 6 years ago

FYI: I am on macOS

kimamula commented 6 years ago

@macbric @martnst I confirmed the following works both on macOS and Windows (with TypeScript@2.8.3).

import { keys } from 'ts-transformer-keys';

interface Props {
  id: string;
  name: string;
  age: number;
}
const keysOfProps = keys<Props>();

console.log(keysOfProps);
const ts = require('typescript');
const keysTransformer = require('ts-transformer-keys/transformer').default;

const program = ts.createProgram(['index.ts'], {
  strict: true,
  noEmitOnError: true,
  target: ts.ScriptTarget.ES5
});

const transformers = {
  before: [keysTransformer(program)],
  after: []
};
const { emitSkipped, diagnostics } = program.emit(undefined, undefined, undefined, false, transformers);

if (emitSkipped) {
  throw new Error(diagnostics.map(diagnostic => diagnostic.messageText).join('\n'));
}
$ node compile # creates index.js
$ node index   # outputs "[ 'id', 'name', 'age' ]"

Could you provide your code so that I can investigate the problem?

ludogithub commented 5 years ago

Hi,

For me the code :

import { keys } from 'ts-transformer-keys';

interface Props {
  id: string;
  name: string;
  age: number;
}
const keysOfProps = keys<Props>();

console.log(keysOfProps);

Gets compiled as :

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ts_transformer_keys_1 = require("ts-transformer-keys");
const keysOfProps = ts_transformer_keys_1.keys();
console.log(keysOfProps);

And serves the error :

TypeError: ts_transformer_keys_1.keys is not a function

On windows, with typescript 2.9.2 and ts-transformer-keys 0.3.3.

Best,

Ludovic

kimamula commented 5 years ago

Hi,

I have listed several ways of how to use custom transformers in README. Which way are you using?

ghost commented 5 years ago

I see you added support for your plugin to awesome-typescript-loader. But unfortunately I switched to ts-loader some time ago because of performance problems: https://github.com/s-panferov/awesome-typescript-loader/issues/570

Any chance of added support in ts-loader?

kimamula commented 5 years ago

@tentreescantbeatme Sorry for the late reply. At that time, I also looked into ts-loader implementation and gave up to add support to it as it looked it is not easy to provide getCustomTransformers() with Program instance.

There is an issue on the ts-loader repository, so someone may working on it. You can use ttypescript for the meantime.

kimamula commented 5 years ago

@tentreescantbeatme this issue was fixed and ts-loader@5.3.3 can provide ts.Program to custom transformers, which enables ts-transformer-keys to work with ts-loader.

Thanos-Pappas commented 5 years ago

Hello, I'm getting the following error. TypeError: Object(...) is not a function on this line console.log( keys<MyInterface>()[0]); I am using the following versions :

A simplified version of my code:

my-inteface.ts

export interface MyInterface{
  keyA: string;
  keyB: string;
  keyC: string;
}

testTransformer.ts

import {keys} from 'ts-transformer-keys';
import {MyInterface} from '../../../interfaces/my-inteface';

export class TestTransformer{
  console.log( keys<MyInterface>()[0]);
}

I followed the webpack configuration as described here

My configurations follow:

angular.json

...
"architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {
              "path": "./extra-webpack.config.js"
            },
...

"serve": {
          "builder": "@angular-builders/dev-server:generic",
...

extra-webpack.config.js

const keysTransformer = require('ts-transformer-keys/transformer').default;
module.exports = {
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'awesome-typescript-loader',
        options: {
          getCustomTransformers: program => ({
  before: [
    keysTransformer(program)
            ]
          })
        }
      }
    ]}};

!! Also i'm getting a worning unused property getCustomTransformers and I run the application with ng serve

Any ideas what is going wrong here?

gabbifish commented 5 years ago

I am also using the same default webpack config as @Thanos-Pappas and am running into:

TypeError: ts_transformer_keys_1.keys is not a function

is there something missing from the webpack demo code? I am also running TS 3.2.2.

zucker-rdrg commented 5 years ago

I have same problem with jasmine-ts and ts-transformer-keys

EDIT: Instead of jasmine-ts I've just used jasmine with ts-node (to pass ts-node --compiler ttypescriptand it works fine :)

kimamula commented 5 years ago

@Thanos-Pappas I tested @angular-builders/custom-webpack with ts-transformer-keys and confirmed TypeError: Object(...) is not a function error.

I found several issues (such as this and this) suggesting that you have to use mergeStrategies: { "module": "prepend" } to apply additional TypeScript transformations with @angular-builders/custom-webpack. However, using mergeStrategies: { "module": "prepend" } results in compilation errors such as the following:

ERROR in [at-loader] ./src/app/app.component.ts:8:5 
    TS2539: Cannot assign to 'AppComponent' because it is not a variable.

This even happens when I use awesome-typescript-loader (or ts-loader) without custom transformers, e.g., like the following:

module.exports = {
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'awesome-typescript-loader' // or 'ts-loader'
      }
    ]
  }
};

It is likely that

  1. TypeScript transformations executed before Angular transformers' transformation are ignored (mergeStrategies: { "module": "append" }, which is default)
  2. TypeScript transformations with awesome-typescript-loader or ts-loader are not possible after Angular transformers' transformation because the TS code is no longer compilable (mergeStrategies: { "module": "prepend" })

Note that webpack loaders are applied from the bottom to the top.

As of now, I cannot think of any good solution for this issue.

@gabbifish I haven't encountered TypeError: ts_transformer_keys_1.keys is not a function with @angular-builders/custom-webpack but this may be also related to you.

YussufElarif commented 5 years ago

I had the same problem i had to follow it using ttypescript.

  1. npm install --save-dev typescript ttypescript
  2. in package.json on "start": use ttsc instead of tsc
    {
    "name": "api",
    "version": "0.0.0",
    "scripts": {
    "start": "ttsc && node ./dist/server",
    "test": "echo \"Error: no test specified\" && exit 1"
    },
    "dependencies": {
    ...
    },
    "devDependencies": {
    ...
    }
  3. in tsconfig.json include plugin -> transform
    {
    "compilerOptions": {
    ...
    "plugins": [
      { 
        "transform": "ts-transformer-keys/transformer"
      }
    ]
    },
    ...
    }

I stopped getting the error after that 😅

simllll commented 5 years ago

For me the issue was that I used the fork-ts-checker-webpack-plugin and therefore set transpileOnly: true. If transpileOnly is true, this plugin does not work. Makes kinda sense, took me still quite a while to figure it out ;).

TLDR: ensure transpileOnly is not set to true!

Regards Simon

ipetrovic11 commented 5 years ago

Hi @kimamula ,

Have you found the way to make this work with Angular or @ngtools/webpack?

The best I was able to do is to patch @ngtools/webpack so it uses ttypescript, but not sure that is sustainable model.

pedrogscruz commented 5 years ago

I had the same problem i had to follow it using ttypescript.

  1. npm install --save-dev typescript ttypescript
  2. in package.json on "start": use ttsc instead of tsc
{
  "name": "api",
  "version": "0.0.0",
  "scripts": {
    "start": "ttsc && node ./dist/server",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    ...
  },
  "devDependencies": {
    ...
  }
  1. in tsconfig.json include plugin -> transform
{
  "compilerOptions": {
    ...
    "plugins": [
      { 
        "transform": "ts-transformer-keys/transformer"
      }
    ]
  },
  ...
}

I stopped getting the error after that

I did exactly the same thing here and it still does not work. My React App get the error TypeError: Object(...) is not a function.

ryoikarashi commented 4 years ago

I'm in the exact same scenario above. Any solution or workaround on this issue?

AmitSharmamad commented 4 years ago

There is no such function as keys in the index.js file, kindly check that

odykyi commented 4 years ago

I have the same error TypeError: ts_transformer_keys_1.keys is not a function

I do not have webpack

I have only tsconfig.json and package.json

How can I fix this error?

kimamula commented 4 years ago

How are you transforming keys()? As listed in README, there are typically 4 ways to transform keys().

dungnguyen10989 commented 4 years ago

How are you transforming keys()? As listed in README, there are typically 4 ways to transform keys().

I'm using TypeScript with React-Native, and error ts_transformer_keys_1.keys still appears, this is my devDendencies:

        "babel-jest": "^24.9.0",
        "babel-plugin-module-resolver": "^4.0.0",
        "eslint": "^6.5.1",
        "eslint-import-resolver-babel-module": "^5.1.2",
        "eslint-plugin-import": "^2.20.2",
        "eslint-plugin-module-resolver": "^0.16.0",
        "jest": "^24.9.0",
        "metro-react-native-babel-preset": "^0.58.0",
        "react-native-schemes-manager": "^2.0.0",
        "react-test-renderer": "16.11.0",
        "reactotron-react-native": "^5.0.0",
        "reactotron-redux": "^3.1.3",
        "reactotron-redux-saga": "^4.2.3",
        "ts-transformer-keys": "0.4.1",
        "tslint": "^6.1.2",
        "ttypescript": "^1.5.10",
        "typescript": "^3.8.3"

and tsconfig.json:

{
    "compilerOptions": {
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "isolatedModules": false,
        "jsx": "react",
        "lib": ["es6", "dom", "es2017"],
        "moduleResolution": "node",
        "noEmit": true,
        "strict": true,
        "target": "esnext",
        "baseUrl": ".",
        "paths": {
            "*": ["src"]
        },
        "plugins": [{ "transform": "ts-transformer-keys/transformer" }]
    },
    "exclude": [
        "node_modules",
        "babel.config.json",
        "metro.config.json",
        "jest.config.json"
    ]
}

How can i fix it?

ArashMotamedi commented 4 years ago

In case this helps anybody else: I was planning to use ttsc but had mistakenly pasted the compilerOptions object into my package.json. The correct place is inside tsconfig.json file.

dungnguyen10989 commented 4 years ago

In case this helps anybody else: I was planning to use ttsc but had mistakenly pasted the compilerOptions object into my package.json. The correct place is inside tsconfig.json file.

Can you show your tsconfig.json and package.json ? I've config like document, but this uncomfortable error still appears.

maddalax commented 4 years ago

I was able to get this working with Create React App by using https://github.com/timarney/react-app-rewired, https://www.npmjs.com/package/ttypescript, and https://www.npmjs.com/package/awesome-typescript-loader

config-overrides.js

module.exports = function override(config, env) {
    config.module.rules.push(  {
        test: /\.(ts|tsx)$/,
        loader: require.resolve('awesome-typescript-loader'),
        options: {
            compiler: 'ttypescript'
        }
    })
    return config;
}

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": false,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "plugins": [
      {
        "transform": "ts-transformer-keys/transformer"
      }
    ]
  },
  "include": [
    "src"
  ],
  "exclude": [
    "node_modules",
    "src/jestTrxProcessor.js",
    "src/test-*.js",
    "src/setupTests.js"
  ]
}
kimamula commented 4 years ago

@dungnguyen10989 If you are using Babel, it is not possible to get the transformer work. See #32.

vmirage commented 4 years ago

I have this issue as well with pnpm when while using ts-node --compiler ttypescript. No issues with ttsc. It seems that the issue here is the filepath mismatch due to symbolic link created by pnpm while using ts-node.

It can be fixed by changing

https://github.com/kimamula/ts-transformer-keys/blob/8a92a56719e97e1e849de5670148f09ff63aaf3f/transformer.ts#L61

to

import * as fs from 'fs';

...

 && (fs.realpathSync(path.join(declaration.getSourceFile().fileName)) === indexTs)

Not sure if this is the right way to fix it. But it works.

kimamula commented 4 years ago

@vmirage Thanks for reporting! I will look for if there is a better way to resolve this problem.

kimamula commented 4 years ago

@vmirage I found that using require.resolve() instead of path.join() works and published the fixed version (v0.4.2). Please give it a try. Thanks again for your report!

vmirage commented 4 years ago

@kimamula yup that works

luisdemarchi commented 3 years ago

@kimamula I arrived late, but unfortunately in the same bug. Using version 0.4.2

TypeError: ts_transformer_keys_1.keys is not a function

kimamula commented 3 years ago

@luisdemarchi please provide a reproduction. Thanks!

benjamingwynn commented 3 years ago

After testing this all day I think neither ts-transformer-keys or ts-interface-keys-transformer work with Webpack ts-loader when onlyCompiledBundledFiles is enabled. It appears as though the typechecker in the transformer code cannot determine the declaration from the symbol because the file is technically not imported as it's not one of the aforementioned "compiled bundle files" (typeChecker.getResolvedSignature(node).signature.declaration in isKeysCallExpression always reads undefined.)

This kind of makes sense, and I've disabled onlyCompiledBundledFiles for now, although that isn't ideal for my production build at all. Maybe somehow manually including the declaration file in the bundled files would fix it (I've tried using include on the webpack ts-loader module rule but to no avail, I'm still learning how to intelligently configure Webpack ). There are some mentions that .d.ts files will be automatically picked up, but the documentation is somewhat scarce (https://github.com/TypeStrong/ts-loader#onlycompilebundledfiles)

the following seem related: https://github.com/TypeStrong/ts-loader/issues/1002, https://stackoverflow.com/a/52034546/3754229

kimamula commented 3 years ago

@benjamingwynn The doc of ts-loader says:

The onlyCompileBundledFiles option modifies this behavior, loading only those files that are actually bundled by webpack, as well as any .d.ts files included by the tsconfig.json settings.

And I confirmed that adding "files": ["node_modules/ts-transformer-keys/index.d.ts"], in tsconfig.json solves the problem. Please give it a try in your build.

benjamingwynn commented 3 years ago

@kimamula thank you for getting back to me! this is correct and solved the issue at hand (...is not a function), but caused my specific case to return [] in place of the keys instead.

I am using node_modules with uncompiled Typescript modules as part of my development environment. If it helps anyone else, ts-loader with onlyCompileBundledFiles won't typecheck against anything in node_modules unless it is either: included in the include array in tsconfig.json as a file path (glob patterns seem to be ignored); or is a .d.ts file included in files. None of this will work unless allowTsInNodeModules is also true.

Edit: cleared up solution

robbiemu commented 3 years ago

I'm on a mac. it seems like it is working for me with ttypecript (vsc hinting shows me that I have an array of union of valid properties), but in ts-jest I am getting this error. I believe my setup is equivalent to what is provided in the readme.. I have the same custom file and this in package.json (instead of jest.config):

  "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node",
    "roots": [
      "<rootDir>/src"
    ],
    "moduleDirectories": [
      "node_modules",
      "src"
    ],
    "moduleNameMapper": {
      "@lib/(.*)": "<rootDir>/src/lib/$1"
    },
    "globals": {
      "ts-jest": {
        "astTransformers": { "before": ["./ts-jest-keys-transformer.js"] }
      }
    }

nvm, I realized that I just forgot to run jest --clearCache first .. it started working when I changed the factory to:

const factory = (cs) => (ctx) => {
  console.log(keysTransformer)
  return keysTransformer(cs.tsCompiler.program)(ctx)
};
stevensnoeijen commented 3 years ago

Got the same problem when running it in vscode with jest-runner, jest --clearCache fixed this problem :)

alexlobera commented 2 years ago

I had to update the factory function to make it work using "ts-jest": "^27.0.4"

// notice cs.program instead of cs.tsCompiler.program
const factory = cs => ctx => keysTransformer(cs.program)(ctx); // 👈 no `tsCompiler`
ahmadalibaloch commented 2 years ago

Using nodejs with ts-node as ts-node ./src/server.ts and getting TypeError: (0 , ts_transformer_keys_1.keys) is not a function

code

import { keys } from 'ts-transformer-keys';

const nestKeys = keys<Nest>();
crackedpotato007 commented 2 years ago

Was this fixed? I am getting the same issue

maranmaran commented 2 years ago

Still ON

keithort commented 2 years ago

For anyone still struggling with this, another fun wrinkle I ran into was that the uses of keys that lived in __tests__ would throw this error. if I moved my tests into the root, then the function was found and executed.

Ghostdog6 commented 2 years ago

We had been using this succesfully, but were having a similar problem when attempting to update our libraries (especially node). I'd updated my devDependencies to use "typescript": "^4.2.3". The server would build, but when trying to use the keys function we'd get an error saying "ts_transformer_keys_1 is not defined".

A coworker noticed that the devDependency on this package was ^3.9.5, so I did the same locally and it works again.

behemoth-thainv commented 2 years ago

I had the same problem i had to follow it using ttypescript.

  1. npm install --save-dev typescript ttypescript
  2. in package.json on "start": use ttsc instead of tsc
{
  "name": "api",
  "version": "0.0.0",
  "scripts": {
    "start": "ttsc && node ./dist/server",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    ...
  },
  "devDependencies": {
    ...
  }
  1. in tsconfig.json include plugin -> transform
{
  "compilerOptions": {
    ...
    "plugins": [
      { 
        "transform": "ts-transformer-keys/transformer"
      }
    ]
  },
  ...
}

I stopped getting the error after that 😅

It's work for me!

nmgix commented 5 months ago

nest.js + basic Jest testing ts-jest + docs helped

jest.json

{
  "moduleFileExtensions": ["js", "json", "ts"],
  "rootDir": "../",
  "testEnvironment": "node",
  "testRegex": ".spec.ts$",
  "transform": {
    "^.+\\.(t|j)s$": "ts-jest"
  },
  "moduleNameMapper": {
    "^src/(.*)$": "<rootDir>/../src/$1"
  },
  "preset": "ts-jest",
  "globals": {
    "ts-jest": {
      "astTransformers": { "before": ["testing/helpers/ts-jest-keys-transformer.js"] }
    }
  }
}

and added ts-jest-keys-transformer.js in same folder

issue is that it warns ts-jest[ts-jest-transformer] (WARN) Define 'ts-jest' config under 'globals' is deprecated.