`styled()` with a mapping makes the class props it adds read-only
メンテナーはふだん 5 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 78/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- react-native, typescript
調査の方向性
まず src/runtime.types.ts にある参照先の StyledComponent と StyledConfiguration の定義を確認し、次に再現テスト src/tests/native/styled-mapped-class-props.test.ts を調べます。対象を絞ったテストを実行し、マップされた class props とマップされていない class props の割り当てを比較します。両方のケースが診断なしで型チェックを通り、テストが成功すれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Before submitting a new issue
- I tested using the latest version of the library, as the bug might be already fixed.
- I tested using a supported version of react native.
- I checked for possible duplicate issues, with possible answers.
Bug summary
styled(component, mapping) takes its mapping as const M extends StyledConfiguration<C>, so a literal such as { className: "style" } is inferred with read-only members, and StyledComponent adds each class prop by mapping over keyof M, which keeps them read-only. Code that sets className on a mapped component's props fails to type-check, while the component's own props and the className of styled() without a mapping are writable.
Library version
main at df32ce3
Environment info
System:
OS: Windows 11 10.0.26300
CPU: "(32) x64 AMD Ryzen 9 9950X3D 16-Core Processor "
Memory: 160.57 GB / 255.67 GB
Binaries:
Node:
version: 26.12.1
path: C:\Program Files\nodejs\node.EXE
Yarn:
version: 4.9.2
path: C:\Users\<user>\AppData\Roaming\npm\yarn.CMD
npm:
version: 12.2.1
path: C:\Program Files\nodejs\npm.CMD
Watchman: Not Found
SDKs:
Android SDK: Not Found
Windows SDK:
AllowDevelopmentWithoutDevLicense: Enabled
Versions:
- 10.0.19041.0
- 10.0.26100.0
IDEs:
Android Studio: AI-262.9437.185.2621.16467767
Visual Studio: Not Found
Languages:
Java:
version: 17.0.20.1
path: C:\Program Files\Microsoft\jdk-17.0.20.101-hotspot\bin\javac.EXE
Ruby: Not Found
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 19.2.3
wanted: 19.2.3
react-native:
installed: 0.86.3
wanted: 0.86.3
react-native-windows: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
Steps to reproduce
- Clone the reproducer branch, which is
mainat df32ce3 with two files added,src/__tests__/native/styled-mapped-class-props.test.tsandreproduce.sh:git clone --branch repro/styled-mapped-class-props-readonly https://github.com/YevheniiKotyrlo/react-native-css cd react-native-css - Run
./reproduce.sh. It runsyarn install --immutableand the test, and ends with one line:DEFECT: …and exit status 1 while the mappedclassNameis read-only,FIXED: …and 0 once it is writable,ERROR: …and 2 when the install fails or a case fails another way, the unmapped control among them.
src/__tests__/native/styled-mapped-class-props.test.ts:
import { join } from "node:path";
import ts from "typescript";
const root = join(__dirname, "../../..").replaceAll("\\", "/");
const fixtureName = `${root}/src/__tests__/native/styled-mapped-class-props.fixture.ts`;
function diagnostics(text: string): readonly string[] {
const { config } = ts.readConfigFile(`${root}/tsconfig.json`, (path) =>
ts.sys.readFile(path),
);
const { options } = ts.parseJsonConfigFileContent(config, ts.sys, root);
const host = ts.createCompilerHost(options, true);
const program = ts.createProgram([fixtureName], options, {
...host,
getCurrentDirectory: () => root,
fileExists: (name) => name === fixtureName || host.fileExists(name),
readFile: (name) => (name === fixtureName ? text : host.readFile(name)),
getSourceFile: (name, languageVersion, ...rest) =>
name === fixtureName
? ts.createSourceFile(name, text, languageVersion, true)
: host.getSourceFile(name, languageVersion, ...rest),
});
return ts
.getPreEmitDiagnostics(program, program.getSourceFile(fixtureName))
.map(({ messageText }) =>
ts.flattenDiagnosticMessageText(messageText, "\n"),
);
}
test("a class prop a styled() mapping adds is as writable as the component's own props", () => {
expect(
diagnostics(
[
`import type { ComponentProps } from "react";`,
`import { Image } from "react-native";`,
`import { styled } from "react-native-css";`,
`const StyledImage = styled(Image, { className: "style" });`,
`type Props = ComponentProps<typeof StyledImage>;`,
`export function withRoundedCorners(props: Props): Props {`,
` const next: Props = { ...props };`,
' next.className = `${props.className ?? ""} rounded`;',
` next.style = props.style;`,
` return next;`,
`}`,
].join("\n"),
),
).toStrictEqual([]);
});
test("the className styled() adds without a mapping is writable", () => {
expect(
diagnostics(
[
`import type { ComponentProps } from "react";`,
`import { View } from "react-native";`,
`import { styled } from "react-native-css";`,
`const StyledView = styled(View);`,
`type Props = ComponentProps<typeof StyledView>;`,
`export function withPadding(props: Props): Props {`,
` const next: Props = { ...props };`,
' next.className = `${props.className ?? ""} p-4`;',
` return next;`,
`}`,
].join("\n"),
),
).toStrictEqual([]);
});
Expected: both cases pass: the className a mapping adds is as writable as the component's own style, and the className of styled() without a mapping stays writable. The script ends with FIXED: 2 of 2 cases pass and exits 0.
Actual: the mapped case reports Cannot assign to 'className' because it is a read-only property., and the unmapped one passes; the script ends with this line and exits 1:
DEFECT: the className a styled() mapping adds is read-only: 1 of 1 cases show it: a class prop a styled() mapping adds is as writable as the component's own props
The run's output on main at df32ce3, Windows 11, Node 26.12.1
System: MINGW64_NT-10.0-26300 3.6.10-5a1665c8.x86_64, Node v26.12.1, Yarn 4.9.2, react-native-css e851452
yarn install --immutable: done
FAIL src/__tests__/native/styled-mapped-class-props.test.ts (73.514 s)
× a class prop a styled() mapping adds is as writable as the component's own props (11460 ms)
√ the className styled() adds without a mapping is writable (5049 ms)
● a class prop a styled() mapping adds is as writable as the component's own props
expect(received).toStrictEqual(expected) // deep equality
- Expected - 1
+ Received + 3
- Array []
+ Array [
+ "Cannot assign to 'className' because it is a read-only property.",
+ ]
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
jest: ran src/__tests__/native/styled-mapped-class-props.test.ts
DEFECT: the className a styled() mapping adds is read-only: 1 of 1 cases show it: a class prop a styled() mapping adds is as writable as the component's own props
Reproducible example repository
https://github.com/YevheniiKotyrlo/react-native-css/tree/repro/styled-mapped-class-props-readonly
- 主要言語
- TypeScript
- スター
- 166
- フォーク
- 45
- 平均マージ
- 12日 1時間
- マージ済み PR(30日)
- 5
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
nativewind/react-native-css のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
nativewind/react-native-css#566 ·
メンテナーはふだん 5 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
nativewind/react-native-css#564 ·
メンテナーはふだん 5 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
nativewind/react-native-css#563 ·
メンテナーはふだん 5 日以内に返信
-
`registerCSS` rejects the `debug: "verbose"` it passes on, and never calls a `logger` it is givenオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
nativewind/react-native-css#562 ·
メンテナーはふだん 5 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
nativewind/react-native-css#561 ·
メンテナーはふだん 5 日以内に返信
nativewind/react-native-css の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
-
🐛 bug
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
LibreChat-AI/LibreChat#17875 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
メンテナーはふだん 1 日以内に返信
-
category:helper tech-debt
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
LanternOps/breeze#11285 ·
メンテナーはふだん 1 日以内に返信
-
area: core area: docs good first issue help wanted lane: free-agent priority: P3 roadmap size: XS type: task
難易度 1/5 1時間未満 初心者へのやさしさ 86/100
arminazimi/seaworthy#701 ·
メンテナーはふだん 1 日以内に返信