Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat:Add support for useDefineForClassFields typescript option (#36335)
* feat:Add support for useDefineForClassFields typescript option * test:add test for useDefineForClassFields option * test: fix lint error
- Loading branch information
1 parent
084a0ca
commit 9fe2f26
Showing
6 changed files
with
238 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { join } from 'path' | ||
import webdriver from 'next-webdriver' | ||
import { createNext, FileRef } from 'e2e-utils' | ||
import { NextInstance } from 'test/lib/next-modes/base' | ||
import { check } from 'next-test-utils' | ||
|
||
describe('useDefineForClassFields SWC option', () => { | ||
let next: NextInstance | ||
|
||
beforeAll(async () => { | ||
next = await createNext({ | ||
files: { | ||
'tsconfig.json': new FileRef( | ||
join(__dirname, 'define-class-fields/tsconfig.json') | ||
), | ||
pages: new FileRef(join(__dirname, 'define-class-fields/pages')), | ||
}, | ||
dependencies: { | ||
mobx: '6.3.7', | ||
typescript: '*', | ||
'@types/react': '*', | ||
'@types/node': '*', | ||
'mobx-react': '7.2.1', | ||
}, | ||
}) | ||
}) | ||
|
||
afterAll(() => next.destroy()) | ||
|
||
it('tsx should compile with useDefineForClassFields enabled', async () => { | ||
let browser | ||
try { | ||
browser = await webdriver(next.appPort, '/') | ||
await browser.elementByCss('#action').click() | ||
await check( | ||
() => browser.elementByCss('#name').text(), | ||
/this is my name: next/ | ||
) | ||
} finally { | ||
if (browser) { | ||
await browser.close() | ||
} | ||
} | ||
}) | ||
|
||
it("Initializes resident to undefined after the call to 'super()' when with useDefineForClassFields enabled", async () => { | ||
let browser | ||
try { | ||
browser = await webdriver(next.appPort, '/animal') | ||
expect(await browser.elementByCss('#dog').text()).toBe('') | ||
expect(await browser.elementByCss('#dogDecl').text()).toBe('dog') | ||
} finally { | ||
if (browser) { | ||
await browser.close() | ||
} | ||
} | ||
}) | ||
|
||
async function matchLogs$(browser) { | ||
let data_foundLog = false | ||
let name_foundLog = false | ||
|
||
const browserLogs = await browser.log('browser') | ||
|
||
browserLogs.forEach((log) => { | ||
if (log.message.includes('data changed')) { | ||
data_foundLog = true | ||
} | ||
if (log.message.includes('name changed')) { | ||
name_foundLog = true | ||
} | ||
}) | ||
return [data_foundLog, name_foundLog] | ||
} | ||
|
||
it('set accessors from base classes won’t get triggered with useDefineForClassFields enabled', async () => { | ||
let browser | ||
try { | ||
browser = await webdriver(next.appPort, '/derived') | ||
await matchLogs$(browser).then(([data_foundLog, name_foundLog]) => { | ||
expect(data_foundLog).toBe(true) | ||
expect(name_foundLog).toBe(false) | ||
}) | ||
} finally { | ||
if (browser) { | ||
await browser.close() | ||
} | ||
} | ||
}) | ||
}) |
53 changes: 53 additions & 0 deletions
53
test/development/basic/define-class-fields/pages/animal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import React from 'react' | ||
|
||
interface Animal { | ||
animalStuff: any | ||
} | ||
interface Dog extends Animal { | ||
dogStuff: any | ||
} | ||
|
||
class AnimalHouse { | ||
resident: Animal | ||
constructor(animal: Animal) { | ||
this.resident = animal | ||
} | ||
} | ||
class DogHouse extends AnimalHouse { | ||
// Initializes 'resident' to 'undefined' | ||
// after the call to 'super()' when | ||
// using 'useDefineForClassFields'! | ||
// @ts-ignore | ||
resident: Dog | ||
// useless constructor only for type checker | ||
/* eslint-disable @typescript-eslint/no-useless-constructor */ | ||
constructor(dog: Dog) { | ||
super(dog) | ||
} | ||
} | ||
|
||
class DogHouseWithDeclare extends AnimalHouse { | ||
declare resident: Dog | ||
// useless constructor only for type checker | ||
/* eslint-disable @typescript-eslint/no-useless-constructor */ | ||
constructor(dog: Dog) { | ||
super(dog) | ||
} | ||
} | ||
|
||
export default function AnimalView() { | ||
const dog = new DogHouse({ | ||
animalStuff: 'animal', | ||
dogStuff: 'dog', | ||
}) | ||
const dogDeclare = new DogHouseWithDeclare({ | ||
animalStuff: 'animal', | ||
dogStuff: 'dog', | ||
}) | ||
return ( | ||
<> | ||
<div id={'dog'}>{dog.resident}</div> | ||
<div id={'dogDecl'}>{dogDeclare.resident?.dogStuff}</div> | ||
</> | ||
) | ||
} |
33 changes: 33 additions & 0 deletions
33
test/development/basic/define-class-fields/pages/derived.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import React from 'react' | ||
|
||
class Base { | ||
set data(value: number) { | ||
console.log('data changed to ' + value) | ||
} | ||
|
||
set name(value: number) { | ||
console.log('name changed to ' + value) | ||
} | ||
} | ||
|
||
class Derived extends Base { | ||
// No longer triggers a 'console.log' | ||
// when using 'useDefineForClassFields'. | ||
// @ts-ignore | ||
name = 10 | ||
constructor() { | ||
super() | ||
//triggers a 'console.log' | ||
this.data = 10 | ||
} | ||
} | ||
|
||
export default function DerivedView() { | ||
const obj = new Derived() | ||
return ( | ||
<> | ||
<div id={'data'}>{obj.data}</div> | ||
<div id={'name'}>{obj.name}</div> | ||
</> | ||
) | ||
} |
39 changes: 39 additions & 0 deletions
39
test/development/basic/define-class-fields/pages/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// @ts-ignore | ||
import { makeObservable, observable } from 'mobx' | ||
// @ts-ignore | ||
import { observer } from 'mobx-react' | ||
import React from 'react' | ||
|
||
class Person { | ||
//Declarations are initialized with Object.defineProperty. | ||
|
||
// @ts-ignore | ||
name: string | ||
|
||
constructor() { | ||
//without useDefineForClassFields it will be error | ||
makeObservable(this, { | ||
name: observable, | ||
}) | ||
} | ||
} | ||
|
||
const person = new Person() | ||
|
||
const PersonView = observer(() => { | ||
const changeName = () => { | ||
person.name = 'next' | ||
} | ||
return ( | ||
<> | ||
<div id="name">this is my name: {person.name}</div> | ||
<button id="action" onClick={changeName}> | ||
Change Name | ||
</button> | ||
</> | ||
) | ||
}) | ||
|
||
export default function Home() { | ||
return <PersonView /> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"compilerOptions": { | ||
"useDefineForClassFields": true, | ||
"esModuleInterop": true, | ||
"module": "esnext", | ||
"jsx": "preserve", | ||
"target": "es5", | ||
"lib": ["dom", "dom.iterable", "esnext"], | ||
"allowJs": true, | ||
"skipLibCheck": false, | ||
"strict": true, | ||
"forceConsistentCasingInFileNames": true, | ||
"noEmit": true, | ||
"incremental": true, | ||
"moduleResolution": "node", | ||
"resolveJsonModule": true, | ||
"isolatedModules": true | ||
} | ||
} |