Skip to content

Commit 6b0d737

Browse files
authored
Remove Omit from Class to align type signatures with runtime beha… (#3959)
1 parent 1b5219c commit 6b0d737

File tree

4 files changed

+206
-1
lines changed

4 files changed

+206
-1
lines changed

.changeset/wet-ladybugs-relax.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
Remove `Omit` from the `Class` interface definition to align type signatures with runtime behavior. This fix addresses the issue of being unable to override base class methods in extended classes without encountering type errors, closes #3958
6+
7+
Before
8+
9+
```ts
10+
import { Schema } from "effect"
11+
12+
class Base extends Schema.Class<Base>("Base")({
13+
a: Schema.String
14+
}) {
15+
f() {
16+
console.log("base")
17+
}
18+
}
19+
20+
class Extended extends Base.extend<Extended>("Extended")({}) {
21+
// Class '{ readonly a: string; } & Omit<Base, "a">' defines instance member property 'f',
22+
// but extended class 'Extended' defines it as instance member function.ts(2425)
23+
// @ts-expect-error
24+
override f() {
25+
console.log("extended")
26+
}
27+
}
28+
```
29+
30+
After
31+
32+
```ts
33+
import { Schema } from "effect"
34+
35+
class Base extends Schema.Class<Base>("Base")({
36+
a: Schema.String
37+
}) {
38+
f() {
39+
console.log("base")
40+
}
41+
}
42+
43+
class Extended extends Base.extend<Extended>("Extended")({}) {
44+
// ok
45+
override f() {
46+
console.log("extended")
47+
}
48+
}
49+
```

packages/effect/dtslint/SchemaClass.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,87 @@ export class FromRefinement
217217
export class FromDoubleRefinement extends S.Class<FromDoubleRefinement>("FromDoubleRefinement")(
218218
S.Struct({ a: S.String }).pipe(S.filter(() => true), S.filter(() => true))
219219
) {}
220+
221+
// ---------------------------------------------
222+
// users can override an instance member property
223+
// ---------------------------------------------
224+
225+
class OverrideBase1 extends S.Class<OverrideBase1>("OverrideBase1")(S.Struct({
226+
a: S.String
227+
})) {
228+
readonly b: number = 1
229+
}
230+
231+
class OverrideExtended1 extends OverrideBase1.extend<OverrideExtended1>(
232+
"OverrideExtended1"
233+
)({
234+
c: S.String
235+
}) {
236+
override readonly b = 2
237+
}
238+
239+
// $ExpectType 2
240+
new OverrideExtended1({ a: "a", c: "c" }).b
241+
242+
// ---------------------------------------------
243+
// users can override an instance member function
244+
// ---------------------------------------------
245+
246+
class OverrideBase2 extends S.Class<OverrideBase2>("OverrideBase2")(S.Struct({
247+
a: S.String
248+
})) {
249+
b(): number {
250+
return 1
251+
}
252+
}
253+
254+
class OverrideExtended2 extends OverrideBase2.extend<OverrideExtended2>(
255+
"OverrideExtended2"
256+
)({
257+
c: S.String
258+
}) {
259+
override b(): 2 {
260+
return 2
261+
}
262+
}
263+
264+
// $ExpectType 2
265+
new OverrideExtended2({ a: "a", c: "c" }).b()
266+
267+
// ---------------------------------------------
268+
// users can override a field with an instance member property
269+
// ---------------------------------------------
270+
271+
class OverrideBase3 extends S.Class<OverrideBase3>("OverrideBase3")(S.Struct({
272+
a: S.String
273+
})) {}
274+
275+
class OverrideExtended3 extends OverrideBase3.extend<OverrideExtended3>(
276+
"OverrideExtended3"
277+
)({
278+
c: S.String
279+
}) {
280+
override readonly a = "default"
281+
}
282+
283+
// $ExpectType "default"
284+
new OverrideExtended3({ a: "a", c: "c" }).a
285+
286+
// ---------------------------------------------
287+
// users can't override an instance member property with a field
288+
// ---------------------------------------------
289+
290+
class OverrideBase4 extends S.Class<OverrideBase4>("OverrideBase4")(S.Struct({
291+
a: S.String
292+
})) {
293+
readonly b = 1
294+
}
295+
296+
class OverrideExtended4 extends OverrideBase4.extend<OverrideExtended4>(
297+
"OverrideExtended4"
298+
)({
299+
b: S.Number
300+
}) {}
301+
302+
// $ExpectType 1
303+
new OverrideExtended4({ a: "a", b: 2 }).b

packages/effect/src/Schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7740,7 +7740,7 @@ export interface Class<Self, Fields extends Struct.Fields, I, R, C, Inherited, P
77407740
new(
77417741
props: RequiredKeys<C> extends never ? void | Simplify<C> : Simplify<C>,
77427742
options?: MakeOptions
7743-
): Struct.Type<Fields> & Omit<Inherited, keyof Fields> & Proto
7743+
): Struct.Type<Fields> & Inherited & Proto
77447744
77457745
/** @since 3.10.0 */
77467746
readonly ast: AST.Transformation

packages/effect/test/Schema/Schema/Class/extend.test.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,76 @@ describe("extend", () => {
118118
expect(b.a()).toEqual("1a")
119119
expect(b.b()).toEqual("1b")
120120
})
121+
122+
it("users can override an instance member property", () => {
123+
class OverrideBase1 extends S.Class<OverrideBase1>("OverrideBase1")(S.Struct({
124+
a: S.String
125+
})) {
126+
readonly b: number = 1
127+
}
128+
129+
class OverrideExtended1 extends OverrideBase1.extend<OverrideExtended1>(
130+
"OverrideExtended1"
131+
)({
132+
c: S.String
133+
}) {
134+
override readonly b = 2
135+
}
136+
137+
expect(new OverrideExtended1({ a: "a", c: "c" }).b).toEqual(2)
138+
})
139+
140+
it("users can override an instance member function", () => {
141+
class OverrideBase2 extends S.Class<OverrideBase2>("OverrideBase2")(S.Struct({
142+
a: S.String
143+
})) {
144+
b(): number {
145+
return 1
146+
}
147+
}
148+
149+
class OverrideExtended2 extends OverrideBase2.extend<OverrideExtended2>(
150+
"OverrideExtended2"
151+
)({
152+
c: S.String
153+
}) {
154+
override b(): 2 {
155+
return 2
156+
}
157+
}
158+
159+
expect(new OverrideExtended2({ a: "a", c: "c" }).b()).toEqual(2)
160+
})
161+
162+
it("users can override a field with an instance member property", () => {
163+
class OverrideBase3 extends S.Class<OverrideBase3>("OverrideBase3")(S.Struct({
164+
a: S.String
165+
})) {}
166+
167+
class OverrideExtended3 extends OverrideBase3.extend<OverrideExtended3>(
168+
"OverrideExtended3"
169+
)({
170+
c: S.String
171+
}) {
172+
override readonly a = "default"
173+
}
174+
175+
expect(new OverrideExtended3({ a: "a", c: "c" }).a).toEqual("default")
176+
})
177+
178+
it("users can't override an instance member property with a field", () => {
179+
class OverrideBase4 extends S.Class<OverrideBase4>("OverrideBase4")(S.Struct({
180+
a: S.String
181+
})) {
182+
readonly b = 1
183+
}
184+
185+
class OverrideExtended4 extends OverrideBase4.extend<OverrideExtended4>(
186+
"OverrideExtended4"
187+
)({
188+
b: S.Number
189+
}) {}
190+
191+
expect(new OverrideExtended4({ a: "a", b: 2 }).b).toEqual(1)
192+
})
121193
})

0 commit comments

Comments
 (0)