Skip to content

Behavior difference: .state emit is missing on react component #4381

Description

@hkleungai

Summary as below.

The table layout is similar to the previous ones in #4332 and #4254. Looks like tsgo over prioritize certain "buggy" behaviour based on .ts file handling, causing this kind of unexpected changes from TS 6 now being surfaced to .js files under tsgo transpilation.

tsc tsgo
Outside ctor, .js .state is emitted .state is emitted
Outside ctor, .ts .state is emitted .state is emitted
Inside ctor, .js .state is emitted .state is not emitted
Inside ctor, .ts .state is not emitted .state is not emitted

Steps to reproduce

  1. Start a plain new project
    • "@types/prop-types": "^15.7.15",
    • "@types/react": "^19.2.17",
    • "@typescript/native-preview": "7.0.0-dev.20260619.1",
    • "typescript": "6.0.3"
  2. Run npx tsgo --init to get the default tsconfig. Turn on these flags as well.
    • "allowJs": true,
    • "checkJs": true,
    • "stableTypeOrdering": true,
  3. Add the below files. Run npx tsc & npx tsgo to see the difference.
/** ========> src/mainJs.js <======== */
import React from 'react';
import PropTypes from 'prop-types';

export class C1 extends React.Component {
    static propTypes = {
        text: PropTypes.string.isRequired,
    }

    state = { count: 0 };
}

export class C2 extends React.Component {
    static propTypes = {
        text: PropTypes.string.isRequired,
    }

    constructor() {
        super({});
        this.state = { count: 0 };
    }
}

/** ========> src/mainTs.ts <======== */
import React from 'react';
import PropTypes from 'prop-types';

export class C1 extends React.Component {
    static propTypes = {
        text: PropTypes.string.isRequired,
    }

    state = { count: 0 };
}

export class C2 extends React.Component {
    static propTypes = {
        text: PropTypes.string.isRequired,
    }

    constructor() {
        super({});
        this.state = { count: 0 };
    }
}

Behavior with typescript@6.0

/** ========> dist/mainJs.d.ts <======== */
export class C1 extends React.Component<any, any, any> {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    constructor(props: any);
    constructor(props: any, context: any);
    state: {
        count: number;
    };
}
export class C2 extends React.Component<any, any, any> {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    constructor();
    state: {
        count: number;
    };
}
import React from 'react';
import PropTypes from 'prop-types';

/** ========> dist/mainTs.d.ts <======== */
import React from 'react';
import PropTypes from 'prop-types';
export declare class C1 extends React.Component {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    state: {
        count: number;
    };
}
export declare class C2 extends React.Component {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    constructor();
}

Behavior with tsgo

/** ========> dist/mainJs.d.ts <======== */
import React from 'react';
import PropTypes from 'prop-types';
export declare class C1 extends React.Component {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    state: {
        count: number;
    };
}
export declare class C2 extends React.Component {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    constructor();
}

/** ========> dist/mainTs.d.ts <======== */
import React from 'react';
import PropTypes from 'prop-types';
export declare class C1 extends React.Component {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    state: {
        count: number;
    };
}
export declare class C2 extends React.Component {
    static propTypes: {
        text: PropTypes.Validator<string>;
    };
    constructor();
}

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions