timocov / ts-transformer-properties-rename Goto Github PK
View Code? Open in Web Editor NEWTypeScript custom transformer to rename properties
License: MIT License
TypeScript custom transformer to rename properties
License: MIT License
Bug report
Input code
class Measure {
height: number;
constructor(public width: number, public ascent: number, public descent: number) {
this.height = ascent + descent;
}
}
export class Foo {}
Expected output
class Measure {
constructor(width, ascent, descent) {
this._internal_width = width;
this._internal_ascent = ascent;
this._internal_descent = descent;
this._internal_height = ascent + descent;
}
}
export class Foo {
}
Actual output
class Measure {
constructor(_internal_width, _internal_ascent, _internal_descent) {
this._internal_width = _internal_width;
this._internal_ascent = _internal_ascent;
this._internal_descent = _internal_descent;
this._internal_height = ascent + descent;
}
}
export class Foo {
}
Additional context
Reproducible if the code above is added as input.ts
to the test directory in this repo and npm run test
is started.
Bug report
Related to timocov/ts-transformer-minify-privates#24
Input code
Enable useDefineForClassFields
compiler option.
class Class {
public declare publicField: number;
protected declare protectedField: number;
private declare privateField: number;
public method() {
console.log(this.publicField, this.protectedField, this.privateField);
}
}
Expected output
var Class = /** @class */ (function () {
function Class() {
}
Object.defineProperty(Class.prototype, "_internal_method", {
enumerable: false,
configurable: true,
writable: true,
value: function () {
console.log(this.publicField, this.protectedField, this.privateField);
}
});
return Class;
}());
Actual output
var Class = /** @class */ (function () {
function Class() {
Object.defineProperty(this, "_internal_publicField", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_internal_protectedField", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_private_privateField", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
Object.defineProperty(Class.prototype, "_internal_method", {
enumerable: false,
configurable: true,
writable: true,
value: function () {
console.log(this._internal_publicField, this._internal_protectedField, this._private_privateField);
}
});
return Class;
}());
@timocov I've tried to use https://github.com/timocov/ts-transformer-properties-rename but couldn't make it work.
How I use ts-transformer-minify-privates
in webpack ts-loader:
import:
import minifyPrivatesTransformer from 'ts-transformer-minify-privates';
use in ts-loader rule:
{
loader: 'ts-loader',
options: {
transpileOnly,
onlyCompileBundledFiles: true,
compilerOptions: {
target: `es${targetEsVersion}`,
importHelpers: true,
jsx: 'preserve',
noUnusedLocals: false
},
getCustomTransformers: transpileOnly ?
undefined :
(program: ts.Program) => ({
before: [
minifyPrivatesTransformer(program)
]
})
}
}
How I try to use ts-transformer-properties-rename
:
const propertiesRenameTransformer = require('ts-transformer-properties-rename').default;
First of all, It's weird ts-transformer-properties-rename
doesn't include d.ts
for types.
Then I replace transform with the new one. Now I have to pass some entrySourceFiles
(with ts-transformer-minify-privates
I don't).
Ok, I try to pass the same entry file as I pass to webpack entry:
propertiesRenameTransformer(program, { entrySourceFiles: [entryFile] })
And get an error:
Error: Cannot find source file /Users/dfilatov/prjs/arcadia/maps/front/services/nmaps/src/client/pages/app-page/nk-app-page.ts
But file /Users/dfilatov/prjs/arcadia/maps/front/services/nmaps/src/client/pages/app-page/nk-app-page.ts
actually exists:
โฏ ls -la /Users/dfilatov/prjs/arcadia/maps/front/services/nmaps/src/client/pages/app-page/nk-app-page.ts
-rw-rw-r-- 1 dfilatov LD\Domain Users 904 Mar 9 2022 /Users/dfilatov/prjs/arcadia/maps/front/services/nmaps/src/client/pages/app-page/nk-app-page.ts
Have no idea how to make it work. Please help.
Originally posted by @dfilatov in timocov/ts-transformer-minify-privates#25 (comment)
The goal of this package is to mangle renamed properties by minifiers like 'terser', but there is an issue, when using class members with decorators. When transformer renames decorated class member with prefix, this class member is mangled by minifier, but it can't handle connection of this class member and decorator function.
Ommiting implementation of __decorate
fn, decorator transform has the following output
// input
class Foo {
@foo private field = 1;
}
// output
class Foo {
constructor() {
this.field = 1;
}
}
__decorate([
foo
], Foo.prototype, "field", void 0);
If use ts-transformer-properties-rename package, it will be transformed to
// input
class Foo {
@foo private _private_field = 1;
}
// output
class Foo {
constructor() {
this._private_field = 1;
}
}
__decorate([
foo
], Foo.prototype, "_private_field", void 0);
But after terser's mangling it will be smth like that
// input
class Foo {
@foo private i = 1;
}
// output
class Foo {
constructor() {
this.i = 1;
}
}
__decorate([
foo
], Foo.prototype, "_private_field", void 0);
There is an issue in terser repo, where contributors assumed, that it could be solved by mangling string literals by same prefix as well, but according issue is still unresolved
Currently the transformer factory requires a ts.Program
as a parameter, but this might not be available yet. I would like it to accept an method that would return the ts.Program instance when needed.
Usecase
When I manipulate the Angular webpack compiler configuration to include this transformer it might not yet have created the ts.Program instance. If it would accept a lazy resolver method, this is not longer an issue:
propertiesRenameTransformer(() => angularCompilerPlugin._getTsProgram(), { entrySourceFiles: angularCompilerPlugin._rootNames })
I can create a PR that would accept both an instance or a method that would return an instance if that would be appreciated.
Bug report
Input code
type Tuple = [number, string] | [];
declare function getTuple(): Tuple;
export function doSomething(): void {
console.log(getTuple().length);
}
Expected output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function doSomething() {
console.log(getTuple().length);
}
exports.doSomething = doSomething;
Actual output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function doSomething() {
console.log(getTuple()._internal_length);
}
exports.doSomething = doSomething;
Related to #8 (comment)
It would be nice if this transformer could also determine internal class names via the entry points and mangle them, if mangling like terser is not feasible then possibly just map class names and the export.classname to a prefixed random set of characters, like cl$AZa
Bug report
Input code
export interface ExportedInterface {
foo: number;
}
export interface AnotherExportedInterface {
bar: number;
isAnother: boolean;
}
export type ExportedType = ExportedInterface | AnotherExportedInterface;
interface NonExportedInterface {
foo: number;
}
interface AnotherNonExportedInterface {
bar: number;
isAnother: boolean;
}
type NonExportedType = NonExportedInterface | AnotherNonExportedInterface;
declare function getNonExported(): NonExportedType;
declare const moveEvent: MouseEvent | TouchEvent;
export function func(type: ExportedType): void {
if ('isAnother' in type) {
console.log(type.bar);
} else {
console.log(type.foo);
}
const nonExportedVar = getNonExported();
if ('isAnother' in nonExportedVar) {
console.log(nonExportedVar.bar);
} else {
console.log(nonExportedVar.foo);
}
if ('onorientationchange' in window || 'button' in moveEvent) {
console.log('check');
}
}
Expected output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function func(type) {
if ('isAnother' in type) {
console.log(type.bar);
}
else {
console.log(type.foo);
}
var nonExportedVar = getNonExported();
if ('_internal_isAnother' in nonExportedVar) {
console.log(nonExportedVar._internal_bar);
}
else {
console.log(nonExportedVar._internal_foo);
}
if ('onorientationchange' in window || 'button' in moveEvent) {
console.log('check');
}
}
exports.func = func;
Actual output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function func(type) {
if ('isAnother' in type) {
console.log(type.bar);
}
else {
console.log(type.foo);
}
var nonExportedVar = getNonExported();
if ('isAnother' in nonExportedVar) {
console.log(nonExportedVar._internal_bar);
}
else {
console.log(nonExportedVar._internal_foo);
}
if ('onorientationchange' in window || 'button' in moveEvent) {
console.log('check');
}
}
exports.func = func;
Bug report
Hello there, I'm tring to set up TypeScript function minification using this lib.
However for some reason it just won't "find" the entry source files I give to it....
My setup is using webpack. See relevant configs below.
I have already tried using the following methods in most combinations:
{ options: { getCustomTransformers: program => ({ before: [ ... ] }) } }
{ loader: require.resolve('ts-loader'), options: { compiler: 'ttypescript', } }
and tsconfig.json
setup...{ loader: require.resolve('awesome-typescript-loader'), }
and tsconfig.json
setup...However, the error message always stays the same: Error: Cannot find source file
.
The weird part is, that the .getSourceFile(...)
method definetley exists on program
when I do a console.log.
It just does not seem to return or actually find the file.
Am I missing something about the config perhaps?
Thanks in advance! I'm really at a loss with this...
tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/tsc",
"target": "es2020",
"module": "commonjs", // commonjs | esnext
"moduleResolution": "node",
"esModuleInterop": true, // TODO
"emitDecoratorMetadata": false,
"sourceMap": false,
"removeComments": true,
"baseUrl": ".",
"paths": {
"three": [
"node_modules/three/src/Three"
]
},
"lib": [
"dom",
"ES5"
],
"plugins": [
{
"transform": "ts-transformer-properties-rename",
"entrySourceFiles": ["./src/AudiOrbi.ts"]
}
]
},
"include": [
"./src/**/*.ts"
],
"exclude": [
"**/*.asc",
"**/better-docs/**"
]
}
webpack.config.js
const path = require('path');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const ENTRY_FILE = path.resolve(__dirname, 'src', 'AudiOrbi.ts');
const BUILD_PATH = path.resolve(__dirname, 'dist');
module.exports = (env) => {
const prod = env.production || false;
return {
mode: 'production',
entry: {
audiorbits: ENTRY_FILE,
},
output: {
chunkFilename: '[id].bundle.js',
path: BUILD_PATH,
},
resolve: {
extensions: ['.ts', '.js'],
},
module: {
rules: [
// TypeScript loader
{
test: /\.tsx?$/,
loader: require.resolve('ts-loader'),
options: {
compiler: 'ttypescript',
configFile: 'tsconfig.json',
transpileOnly: true,
},
},
......
],
},
plugins: [
// The TS Syntax checking
new ForkTsCheckerWebpackPlugin({}),
.......
],
// remove dead code in production
optimization: prod ? {
minimizer: [
new TerserPlugin({
// https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
terserOptions: {
parse: {},
compress: {
unsafe: true,
pure_funcs: ['console.warn'], // ~40kb of three.js messages... errors will stil come through.
},
mangle: {
properties: {
regex: /^_(private|internal)_/, // the same prefixes like for custom transformer
},
},
module: true,
sourceMap: false,
},
}),
],
}: {},
};
};
Error output
// place your code here
./src/AudiOrbi.ts 39 bytes [built] [code generated] [1 error]
ERROR in ./src/AudiOrbi.ts
Module build failed (from ./node_modules/ts-loader/index.js):
Error: Cannot find source file ./src/AudiOrbi.ts
at ExportsSymbolTree.computeTreeForExports (D:\MyProject\node_modules\ts-transformer-properties-rename\dist\exports-symbol-tree.js:27:23)
at new ExportsSymbolTree (D:\MyProject\node_modules\ts-transformer-properties-rename\dist\exports-symbol-tree.js:10:14)
at createTransformerFactory (D:\MyProject\node_modules\ts-transformer-properties-rename\dist\transformer.js:38:29)
at propertiesRenameTransformer (D:\MyProject\node_modules\ts-transformer-properties-rename\dist\transformer.js:32:12)
at createTransformerFromPattern (D:\MyProject\node_modules\ttypescript\lib\PluginCreator.js:40:19)
at PluginCreator.createTransformers (D:\MyProject\node_modules\ttypescript\lib\PluginCreator.js:123:31)
at Object.newEmit [as emit] (D:\MyProject\node_modules\ttypescript\lib\patchCreateProgram.js:68:52)
at Object.transpileModule (D:\MyProject\node_modules\typescript\lib\typescript.js:131713:17)
at getTranspilationEmit (D:\MyProject\node_modules\ts-loader\dist\index.js:388:75)
at successLoader (D:\MyProject\node_modules\ts-loader\dist\index.js:37:11)
Bug report
Input code
export class testProperties {
public thank: number = 0;
public you: number = 0;
public painInTheButton0: number = 0;
public painInTheButton1: number = 0;
public painInTheButton2: number = 0;
}
var test = new testProperties();
test.thank = 0;
test.you = 0;
for (var i = 0; i < 3; i++)
test['painInTheButton' + i] = i;
var totalThanks = test.thank + 1;
var totalForYou = test['you'] + 0;
var button1Result = test.painInTheButton1;
var button2Result = test['painInTheButton' + 2];
var button3Result = test['painInTheButton3'];
Expected output
error: testProperties.ts:13 Computed property, use /** @ignore-rename:[painInTheButton0,painInTheButton1,painInTheButton2] @ignore-computed-property */
error: testProperties.ts:18 Invalid property, use /** @ignore-invalid-property */
Actual output
(function(exports){
exports.testProperties = void 0;
var testProperties = (function () {
function testProperties() {
this._internal_thank = 0;
this._internal_you = 0;
this._internal_painInTheButton0 = 0;
this._internal_painInTheButton1 = 0;
this._internal_painInTheButton2 = 0;
}
return testProperties;
}());
exports.testProperties = testProperties;
var test = new testProperties();
test._internal_thank = 0;
test._internal_you = 0;
for (var i = 0; i < 3; i++)
test['painInTheButton' + i] = i;
var totalThanks = test._internal_thank + 1;
var totalForYou = test["_internal_you"] + 0;
var button1Result = test._internal_painInTheButton1;
var button2Result = test['painInTheButton' + 2];
var button3Result = test['painInTheButton3'];
})(output);
Additional context
The two issues are...
1. 'painInTheButton' + i wont get renamed to '_internal_painInTheButton' + i, even if it did, terser wouldn't be able to rename that property to the mapped mangle.
2. 'painInTheButton3' doesn't exist on the object, since I only defined up to 2.
I would prefer these computed and invalid properties to throw an error when compiling, and if I want to ignore them have some option to do so. I would rather not find the bug through user report :(
The reason I would think the invalid property should error is to specifically review, and then can change to warn about it, or ignore it
Currently the transformer trying to figure out visibility type of every particular node, what allows minify properties better.
Needs to add "loose" mode, what will use the only name of the property (rather that type/symbol) to detect visibility type.
For example,
export interface Foo {
prop: number;
}
export class Bar implements Foo {
prop: number = 123;
}
class Baz {
prop: number = 321;
}
In the current mode we'll rename Baz::prop
to Baz::_internal_prop
, but Bar::prop
will be unchanged.
In "loose" mode we won't rename Baz::prop
, because there is another "public" property with the same name prop
(but in Bar
class). So, we'll just pop-up all "public" properties and use that set of names only.
Bug report
I believe it's one of the optimisations TypeScript compiler is doing, like type interning, but the type of the object literal can be "erased" down to an anonymous type when used in combination with generic function.
The examples below give more context.
The Model
interface is annotated as @public
and should not be minified.
However, when the generic context
function gets in the middle, the type checker ends up "erasing" the type of the object literal being returned, i.e. instead of type being Model
it becomes an anonymous { param1: string, param2: string }
.
As a result the minifier will now minify property names it should not, breaking the code.
Input code
/** @public */
interface Model {
param1: string;
param2: string;
}
export declare function context<Result>(name: string, producer: () => Result): Result;
export function exampleWithGeneric(param1: string, param2: string): Model {
return context("contextName", () => {
return {
param1: param1,
param2: param2,
};
});
}
export function exampleWithGenericAndAnnotation(param1: string, param2: string): Model {
return context<Model>("contextName", () => {
return {
param1: param1,
param2: param2,
};
});
}
export function exampleWithoutGeneric(param1: string, param2: string): Model {
return {
param1: param1,
param2: param2,
};
}
Expected output
/** @public */
interface Model {
param1: string;
param2: string;
}
export declare function context<Result>(name: string, producer: () => Result): Result;
export function exampleWithGeneric(param1: string, param2: string): Model {
return context("contextName", () => {
return {
param1: param1,
param2: param2,
};
});
}
export function exampleWithGenericAndAnnotation(param1: string, param2: string): Model {
return context<Model>("contextName", () => {
return {
param1: param1,
param2: param2,
};
});
}
export function exampleWithoutGeneric(param1: string, param2: string): Model {
return {
param1: param1,
param2: param2,
};
}
Actual output
/** @public */
interface Model {
param1: string;
param2: string;
}
export declare function context<Result>(name: string, producer: () => Result): Result;
export function exampleWithGeneric(param1: string, param2: string): Model {
return context("contextName", () => {
return {
_internal_param1: param1,
_internal_param2: param2,
};
});
}
export function exampleWithGenericAndAnnotation(param1: string, param2: string): Model {
return context<Model>("contextName", () => {
return {
param1: param1,
param2: param2,
};
});
}
export function exampleWithoutGeneric(param1: string, param2: string): Model {
return {
param1: param1,
param2: param2,
};
}
Additional context
It's worth noting that it seems to be how TypeScript compiler resolves types.
Even VS Code's LSP indicates it.
Annotating generic functions with type signature is an option, but not a very reliable one because I don't think there's a way to enforce it.
If there's such option with linter or compiler that'd be nice.
It feels like transformer plugin has to do the work compiler chose not to.
E.g. if object literal is part of return statement then the plugin would have to analyse return type of the parent function and then all the other parent functions all the way up to the top (source file) and check if any of those types is external or annotated with @public
.
Bug report
Input code
class Foo<Type extends string> {
public search(): void {}
}
type StringFoo<T extends string> = Foo<T>;
class Bar {
private foo: StringFoo<string> = new Foo();
public doSomething(): void {
this.foo.search();
}
}
export interface FooBar {}
Expected output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype._internal_search = function () { };
return Foo;
}());
var Bar = /** @class */ (function () {
function Bar() {
this._private_foo = new Foo();
}
Bar.prototype._internal_doSomething = function () {
this._private_foo._internal_search();
};
return Bar;
}());
Actual output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Foo = /** @class */ (function () {
function Foo() {
}
Foo.prototype._internal_search = function () { };
return Foo;
}());
var Bar = /** @class */ (function () {
function Bar() {
this._private_foo = new Foo();
}
Bar.prototype._internal_doSomething = function () {
this._private_foo.search();
};
return Bar;
}());
Enum members are not renamed, but member access is renamed resulting in potential runtime errors.
export enum TestEnum {
Test1,
Test2,
Test3,
}
Results in:
export var TestEnum;
(function (TestEnum) {
TestEnum[TestEnum["Test1"] = 0] = "Test1";
TestEnum[TestEnum["Test2"] = 1] = "Test2";
TestEnum[TestEnum["Test3"] = 2] = "Test3";
})(TestEnum || (TestEnum = {}));
Member access results in:
console.log(TestEnum._internal_Test1);
Which does not exist.
Bug report
Input code
// This will be an internal class determined by entry point
export class testProperties {
private _salad: number = 0;
public dressing: number = 0;
public get salad(): number { return this._salad; }
public set salad(val: number) { this._salad = val; }
}
var test = new testProperties();
test.salad = 0;
test.dressing = 0;
var totalSalad = test.salad + 1;
var totalDressing = test.dressing + 0;
Expected output
(function(exports){
exports.testProperties = void 0;
var testProperties = (function () {
function testProperties() {
this._private__salad = 0;
this._internal_dressing = 0;
}
Object.defineProperty(testProperties.prototype, "_internal_salad", {
get: function () { return this._private__salad; },
set: function (val) { this._private__salad = val; },
enumerable: false,
configurable: true
});
return testProperties;
}());
exports.testProperties = testProperties;
var test = new testProperties();
test._internal_salad = 0;
test._internal_dressing = 0;
var totalSalad = test._internal_salad + 1;
var totalDressing = test._internal_dressing + 0;
})(output);
Actual output
(function(exports){
exports.testProperties = void 0;
var testProperties = (function () {
function testProperties() {
this._private__salad = 0;
this._internal_dressing = 0;
}
Object.defineProperty(testProperties.prototype, "salad", {
get: function () { return this._private__salad; },
set: function (val) { this._private__salad = val; },
enumerable: false,
configurable: true
});
return testProperties;
}());
exports.testProperties = testProperties;
var test = new testProperties();
test._internal_salad = 0;
test._internal_dressing = 0;
var totalSalad = test._internal_salad + 1;
var totalDressing = test._internal_dressing + 0;
})(output);
Additional context
The "salad" argument of Object.defineProperty was not renamed to "_internal_salad"
Bug report
Input code
function func(): unknown {
const b = { value: 321 } as unknown;
const c = { int: 222 } as unknown as InternalInterface;
return {
foo: 1,
bar: b,
baz: 3,
c: c,
};
}
function func2(): any {
const b = { value: 321 } as any;
const c = { field: 222 } as any as InternalInterface;
return {
foo: 1,
bar: b,
baz: 3,
c: c,
};
}
Expected output
function func() {
var b = { value: 321 };
var c = { _internal_int: 222 };
return {
foo: 1,
bar: b,
baz: 3,
c: c,
};
}
function func2() {
var b = { value: 321 };
var c = { _internal_field: 222 };
return {
foo: 1,
bar: b,
baz: 3,
c: c,
};
}
Actual output
function func() {
var b = { _internal_value: 321 };
var c = { _internal_int: 222 };
return {
_internal_foo: 1,
_internal_bar: b,
_internal_baz: 3,
_internal_c: c,
};
}
function func2() {
var b = { _internal_value: 321 };
var c = { _internal_field: 222 };
return {
_internal_foo: 1,
_internal_bar: b,
_internal_baz: 3,
_internal_c: c,
};
}
Bug report
Input code
interface Foo {
field: string;
field2: number;
}
type ReadonlyFoo = Readonly<Foo>;
function bar(foo: ReadonlyFoo): void {
console.log(foo.field, foo.field2);
}
function baz(): void {
const foo: Foo = {
field: '',
field2: 0,
};
bar(foo);
bar({
field: '',
field2: 0,
});
}
Expected output
function bar(foo) {
console.log(foo._internal_field, foo._internal_field2);
}
function baz() {
var foo = {
_internal_field: '',
_internal_field2: 0,
};
bar(foo);
bar({
_internal_field: '',
_internal_field2: 0,
});
}
Actual output
function bar(foo) {
console.log(foo.field, foo.field2);
}
function baz() {
var foo = {
_internal_field: '',
_internal_field2: 0,
};
bar(foo);
bar({
field: '',
field2: 0,
});
}
Additional context
Broken in #15
Bug report
When I do not specify return type to public functions the returning literal object is transformed to the object with internal properties.
Input code
function fn(input: { test1: number; test2: string }): { a: number; b: string } {
return {
a: 2,
b: 'str',
};
}
export function fn2(input: { test1: number; test2: string }) {
const { a } = fn({ test1: 25, test2: 'test' });
return {
a,
b: 'str',
};
}
Expected output
function fn(input) {
return {
_internal_a: 2,
_internal_b: 'str',
};
}
function fn2(input) {
const { _internal_a: a } = fn();
return {
a,
b: 'str',
};
}
export { fn2 };
Actual output
function fn(input) {
return {
_internal_a: 2,
_internal_b: 'str',
};
}
function fn2(input) {
const { _internal_a: a } = fn();
return {
_internal_a: a,
_internal_b: 'str',
};
}
export { fn2 };
Additional context
If I specify return type explicitly it works as expected
function fn(input: { test1: number; test2: string }): { a: number; b: string } {
return {
a: 2,
b: 'str',
};
}
export function fn2(input: { test1: number; test2: string }): { a: number; b: string } { // this is the only change as return type is explicit now
const { a } = fn({ test1: 25, test2: 'test' });
return {
a,
b: 'str',
};
}
Bug report
Input code
export interface Ohlc {
open: number;
high: number;
low: number;
close: number;
}
export interface BarValueByType {
Bar: Ohlc;
Line: number;
}
export type SeriesType = keyof BarValueByType;
export function getBarValue<T extends SeriesType>(value: number, seriesType: T): BarValueByType[T] {
if (seriesType === 'Bar') {
return {
open: value,
high: value,
low: value,
close: value,
} as BarValueByType[T];
} else {
return value as BarValueByType[T];
}
}
Expected output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBarValue = void 0;
function getBarValue(value, seriesType) {
if (seriesType === 'Bar') {
return {
open: value,
high: value,
low: value,
close: value,
};
}
else {
return value;
}
}
exports.getBarValue = getBarValue;
Actual output
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBarValue = void 0;
function getBarValue(value, seriesType) {
if (seriesType === 'Bar') {
return {
_internal_open: value,
_internal_high: value,
_internal_low: value,
_internal_close: value,
};
}
else {
return value;
}
}
exports.getBarValue = getBarValue;
Mapped types do not appear to respect @public jsdoc
/** @public */
export type TestKey = "a" | "b";
/** @public */
export type TestMappedType = {
/** @public */
[P in TestKey]?: {};
};
class TestMappedClass {
/** @public */
private testMapped: TestMappedType = {};
public constructor() {
this.testMapped.a = {};
}
}
Results in
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var TestMappedClass = /** @class */ (function () {
function TestMappedClass() {
/** @public */
this._private_testMapped = {};
this._private_testMapped._internal_a = {};
}
return TestMappedClass;
}());
Note: I tried it using Record as well and it has the same issue
There is types
and typesRoot
compiler options, which allows you declare types from custom packages. Needs to change detecting whether the package is from external module to handle this.
I notice that if I quote the attribute it is not (and I like it!):
I'd say this is a bug tbh ๐ I'll fix this later.
I think that this is a bug because this tool relies on the type information rather than the syntax so whatever syntax you use it should work the same IMO.
Originally posted by @timocov in #29 (comment)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.