Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom and Extended Types #3785

Closed
wants to merge 66 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
38a0ecc
added custom types
mdmjg Jul 13, 2020
0312ee5
files
mdmjg Jul 13, 2020
82c254d
more extensions
mdmjg Jul 13, 2020
62a8aaa
files
mdmjg Jul 13, 2020
f1b329f
changed fixtures
mdmjg Jul 13, 2020
c6c86e7
changes eslint file
mdmjg Jul 13, 2020
14400a5
changed element.children to descendant
mdmjg Jul 17, 2020
821b814
updated types
mdmjg Jul 20, 2020
1e929c6
more type changes
mdmjg Jul 20, 2020
4cf3745
changed a lot of typing, still getting building errors
mdmjg Jul 20, 2020
e0a9be6
extended text type in slate-react
mdmjg Jul 20, 2020
df9c098
removed type assertions
mdmjg Jul 21, 2020
0fe3788
Clean up of custom types and a couple uneeded comments.
BrentFarese Jul 24, 2020
304c9cd
Rename headingElement-true.tsx.tsx to headingElement-true.tsx
mdmjg Jul 24, 2020
052ef78
moved basetext and baselement
mdmjg Jul 24, 2020
d086d98
Update packages/slate/src/interfaces/text.ts
mdmjg Jul 24, 2020
395d91e
Fix some type issues with core functions.
BrentFarese Jul 24, 2020
cc7fd88
Merge branch 'custom-types' of github.com:arity-contracts/slate into …
BrentFarese Jul 24, 2020
a60e065
Clean up text and element files.
BrentFarese Jul 24, 2020
18b47f2
Convert other types to extended types.
BrentFarese Jul 24, 2020
d5d816a
Change the type of editor.marks to the appropriate type.
BrentFarese Jul 29, 2020
329e44e
Add version 100.0.0 to package.json
timbuckley Jul 30, 2020
ccfbead
Merge branch 'master' of github.com:arity-contracts/slate
timbuckley Jul 30, 2020
3b70b09
Revert "Add version 100.0.0 to package.json"
timbuckley Jul 30, 2020
4f652d9
added custom types
mdmjg Jul 13, 2020
e55260b
files
mdmjg Jul 13, 2020
6dc5c3e
more extensions
mdmjg Jul 13, 2020
8d7e318
files
mdmjg Jul 13, 2020
7368fd9
changed fixtures
mdmjg Jul 13, 2020
82c8f97
changes eslint file
mdmjg Jul 13, 2020
d3daf18
changed element.children to descendant
mdmjg Jul 17, 2020
de6ba2b
updated types
mdmjg Jul 20, 2020
8ee9d1e
more type changes
mdmjg Jul 20, 2020
f4be265
changed a lot of typing, still getting building errors
mdmjg Jul 20, 2020
f250ca6
extended text type in slate-react
mdmjg Jul 20, 2020
01204fb
removed type assertions
mdmjg Jul 21, 2020
8daeef0
Clean up of custom types and a couple uneeded comments.
BrentFarese Jul 24, 2020
c52308b
Rename headingElement-true.tsx.tsx to headingElement-true.tsx
mdmjg Jul 24, 2020
e0e7463
moved basetext and baselement
mdmjg Jul 24, 2020
d42a3e2
Update packages/slate/src/interfaces/text.ts
mdmjg Jul 24, 2020
88c15bd
Fix some type issues with core functions.
BrentFarese Jul 24, 2020
e102403
Clean up text and element files.
BrentFarese Jul 24, 2020
fcd2bdf
Convert other types to extended types.
BrentFarese Jul 24, 2020
81383bf
Change the type of editor.marks to the appropriate type.
BrentFarese Jul 29, 2020
bfac456
Run prettier clean up.
BrentFarese Jul 30, 2020
f8b7568
Run linter.
BrentFarese Jul 30, 2020
faa5274
Remove key:string uknown from the base types.
BrentFarese Jul 31, 2020
8264419
Clean up types after removing key:string unknown.
BrentFarese Jul 31, 2020
aa3a235
Lint and prettier fixes.
BrentFarese Jul 31, 2020
51ad8ef
Merge branch 'master' of https://github.com/ianstormtaylor/slate
timbuckley Aug 11, 2020
dbb2072
Merge branch 'master' of https://github.com/ianstormtaylor/slate
timbuckley Aug 19, 2020
d20085f
Implement custom-types
timbuckley Aug 11, 2020
9c311ae
merge changes
mdmjg Aug 19, 2020
2a94b1f
added custom types to examples
mdmjg Aug 19, 2020
95d4d5d
Merge branch 'custom-types' of https://github.com/arity-contracts/sla…
mdmjg Aug 19, 2020
dd2aa6f
reset yarn lock
mdmjg Aug 20, 2020
37ed24d
added ts to fixtures
mdmjg Aug 20, 2020
ec1e876
examples custom types
mdmjg Aug 20, 2020
43046f4
Set yarn.lock back to match master
timbuckley Aug 20, 2020
d91a75a
Fixup Transforms mergine in index
timbuckley Aug 20, 2020
3f4bcda
(m) Bring back editor.children Node[] coerc
timbuckley Aug 20, 2020
c576beb
(m) Fully bring yarn.lock back to before
timbuckley Aug 20, 2020
7dd9ff2
Fix type coersion on editor.children
timbuckley Aug 20, 2020
ff2b19f
custom-types.ts -> custom-types.d.ts
timbuckley Aug 20, 2020
e328ca7
Use thesunny's version of transforms/index
timbuckley Aug 20, 2020
84448f6
Excluded .ts files from test.
BrentFarese Aug 20, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions packages/slate/src/create-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const createEditor = (): Editor => {
marks: null,
isInline: () => false,
isVoid: () => false,
onChange: () => { },
onChange: () => {},

apply: (op: Operation) => {
for (const ref of Editor.pathRefs(editor)) {
Expand Down Expand Up @@ -214,10 +214,10 @@ export const createEditor = (): Editor => {
const shouldHaveInlines = Editor.isEditor(node)
? false
: Element.isElement(node) &&
(editor.isInline(node) ||
node.children.length === 0 ||
Text.isText(node.children[0]) ||
editor.isInline(node.children[0] as Element))
(editor.isInline(node) ||
node.children.length === 0 ||
Text.isText(node.children[0]) ||
editor.isInline(node.children[0] as Element))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be staying away from type assertions, if at all possible. There is a way to have the same code here w/o the type assertion.


// Since we'll be applying operations while iterating, keep track of an
// index that accounts for any added/removed nodes.
Expand Down
9 changes: 2 additions & 7 deletions packages/slate/src/interfaces/custom-extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,23 @@ import { Descendant } from 'slate';
import { Descendant } from 'slate';
* The `CustomExtensions` interface extends types
*/
import { Descendant } from './node';
import { Descendant } from './node'

export interface BaseElement {
children: Descendant[]
}

// This would be Text as per Slate's definition
export type BaseText = {
export interface BaseText {
text: string
}

export interface CustomExtensions {
Copy link
Collaborator

@BrentFarese BrentFarese Jul 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think we need to update Slate's types for Text and Element to use ExtendedType below? See @thesunny suggestion in the implementation issue - #3725. For instance:

// This would be Element as per Slate's definition
export type BaseElement = {
  children: Text[]
}

// This would be Text as per Slate's definition
export type BaseText = {
  text: string
}

export type Text = ExtendedType<"Text", BaseText>
export type Element = ExtendedType<"Element", BaseElement>

Then, the exported new types for Text and Element would be used in Slate's codebase and any developer's use of CustomExtensions and ExtendedType would propagate to the rest of the codebase.

Let's discuss if needed.

Copy link
Contributor Author

@mdmjg mdmjg Jul 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with this is that when you use ExtendedType you are redefining Element or Text according to the definition you gave it inside your CustomExtension (once the user has defined it). If make the extended Element the new Element, a bunch of errors will be thrown during build, and pretty much 60% of the testcases will fail. Something that I found while making this PR was that in order to call Element's functions like isElement, you need to use an alias. If you take a look at my isElement test case, you will see I am calling BaseElement.isElement. If I were to use Element.isElement, the program would not recognize the function because the type Extension is not able to fetch the functions as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I haven't had time to dive into the code so perhaps you could explain the issue and I might be able to help with a solution.

My question is, if the original object is defined as BaseText or BaseElement, and the extended type is created as Text and Element, are you saying that the methods don't come through to the extend type? It looks like in the typing we are doing:

export type ExtendedType<K extends string, B> =
  unknown extends CustomExtensions[K]
  ? B
  : B & CustomExtensions[K]

So shouldn't we get the proper types from both the original with the extensions added (ie. B & CustomExtensions[K])?

I may be misunderstanding the issue in which case a clarification would be helpful. Thanks.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thesunny could use a review from your end. I think the code is looking more final now so it's probably a good time to review. Thanks!

@CameronAckermanSEL can you review too?

[key: string]: unknown
}


// prettier-ignore
export type ExtendedType<K extends string, B> =
unknown extends CustomExtensions[K]
? B
: B | CustomExtensions[K]




4 changes: 2 additions & 2 deletions packages/slate/src/interfaces/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export const Element = {
},

/**
* Check if some props are a partial of element.
*/
* Check if a value is an array of `Element` objects.
*/

isElementProps(props: any): props is Partial<Element> {
return !!props.children
Expand Down
14 changes: 9 additions & 5 deletions packages/slate/src/interfaces/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export const Node = {
}
}

delete r.selection
if (Editor.isEditor(r)) delete r.selection
cameracker marked this conversation as resolved.
Show resolved Hide resolved
})

return newRoot.children
Expand Down Expand Up @@ -354,8 +354,12 @@ export const Node = {

matches(node: Node, props: Partial<Node>): boolean {
return (
(Element.isElement(node) && Element.isElementProps(props) && Element.matches(node, props)) ||
(Text.isText(node) && Text.isTextProps(props) && Text.matches(node, props))
(Element.isElement(node) &&
Element.isElementProps(props) &&
Element.matches(node, props)) ||
(Text.isText(node) &&
Text.isTextProps(props) &&
Text.matches(node, props))
)
},

Expand Down Expand Up @@ -468,7 +472,7 @@ export const Node = {
if (Text.isText(node)) {
return node.text
} else {
let children = node.children as Array<Descendant>
const children = node.children as Array<Descendant>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array<x> is more commonly written as x[]

Suggested change
const children = node.children as Array<Descendant>
const children = node.children as Descendant[]

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tim is totally correct but we should avoid the type assertion, if we can.

return children.map(Node.string).join('')
}
},
Expand All @@ -477,7 +481,7 @@ export const Node = {
* Return an iterable of all leaf text nodes in a root node.
*/

* texts(
*texts(
root: Node,
options: {
from?: Path
Expand Down
7 changes: 3 additions & 4 deletions packages/slate/src/interfaces/text.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import isPlainObject from 'is-plain-object'
import { Range } from '..'
import { BaseText, ExtendedType } from "./custom-extensions"

import { BaseText, ExtendedType } from './custom-extensions'

/**
* `Text` objects represent the nodes that contain the actual text content of a
Expand Down Expand Up @@ -66,8 +65,8 @@ export const Text = {
},

/**
* Check if some props are a partial of element.
*/
* Check if some props are a partial of element.
*/

isTextProps(props: any): props is Partial<Text> {
return !!props.children
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import {
Element,
Node,
CustomExtensions,
ExtendedType, Descendant
ExtendedType,
Descendant,
} from 'slate'

declare module 'slate' {
interface CustomExtensions {
Element:
| { type: 'heading'; level: number; children: Descendant[] }
| { type: 'list-item'; depth: number; children: Descendant[] }
| { type: 'heading'; level: number; children: Descendant[] }
| { type: 'list-item'; depth: number; children: Descendant[] }
}
}


const extension: CustomExtensions = {
Element: { type: 'heading', level: 5, children: [] },
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
// show that regular methods that are imported work as expected
import {
CustomExtensions,
Element as BaseElement,
Node,
} from 'slate'
import { CustomExtensions, Element as BaseElement, Node } from 'slate'

declare module 'slate' {
interface CustomExtensions {
5: string
}
}


// if Element does not have a 'children' property, it is not an element
const extension: CustomExtensions = {
5: "I'm a number"
5: "I'm a number",
}

export const input = extension
Expand Down