-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
refactor(blocks): Migrate blocks/text.js
to TypeScript
#6958
Conversation
@cpcallen fyi I made a start on the text blocks, but will need type help to disentangle some of the combinations of extensions and mixins. |
blocks/text.ts
Outdated
@@ -339,15 +334,15 @@ blocks['text_getSubstring'] = { | |||
const menu = fieldRegistry.fromJson({ | |||
type: 'field_dropdown', | |||
options: this['WHERE_OPTIONS_' + n], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cpcallen What do you think I should do for this dynamic access to WHERE_OPTIONS_1
and WHERE_OPTIONS_2
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First I would try typing the parameter n: 1|2
, which should probably be the case in any case.
If that doesn't fix a type error here then I'd try this just in case it helps:
options: this['WHERE_OPTIONS_' + n], | |
options: this['WHERE_OPTIONS_' + (n as 1|2)], |
but probably it wouldn't, so then it might be necessary to resort to :
options: this['WHERE_OPTIONS_' + n], | |
options: this[('WHERE_OPTIONS_' + n) as 'WHERE_OPTIONS_1'|'WHERE_OPTIONS_2'], |
…and if that doesn't work then maybe ultimately it might be necessary to do something like:
options: this['WHERE_OPTIONS_' + n], | |
options: n === 1 ? this.WHERE_OPTIONS_1 : this.WHERE_OPTIONS_2; |
(but I'd really rather we didn't!)
blocks/text.ts
Outdated
@@ -282,7 +279,7 @@ blocks['text_getSubstring'] = { | |||
* @return {!Element} XML storage element. | |||
* @this {Block} | |||
*/ | |||
mutationToDom: function() { | |||
mutationToDom: function(this: Block): Element { | |||
const container = xmlUtils.createElement('mutation'); | |||
const isAt1 = this.getInput('AT1').type === ConnectionType.INPUT_VALUE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cpcallen this.getInput('AT')
is possible null, because it's added and removed dynamically. Is there a way to guarantee that it's present, or should I just use !
to assert that it is non-null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for now just use !
(since we presume the existing code is not broken), but then in the next pass we actually add checks for these things (via ?.
where convenient and more explicitly via if (bad) throw new SomeError()
where necessary).
blocks/text.js
to TypeScript
@cpcallen this is ready for review! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cpcallen this is ready for review!
Don't forget to update the PR description.
const isAt2 = this.getInput('AT2').type === ConnectionType.INPUT_VALUE; | ||
container.setAttribute('at2', isAt2); | ||
const isAt1 = this.getInput('AT1')!.type === ConnectionType.INPUT_VALUE; | ||
container.setAttribute('at1', `${isAt1}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I had a look recently to see if String(x)
or `${x}`
to typecast the second parameter of setAttribute
calls. We use both, with String
being slightly more popular.
*/ | ||
compose: function(containerBlock) { | ||
let itemBlock = containerBlock.getInputTargetBlock('STACK'); | ||
compose: function(this: JoinMutatorBlock, containerBlock: Block) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
containerBlock
could be a more specific type, if you define one.
blocks/text.ts
Outdated
compose: function(containerBlock) { | ||
let itemBlock = containerBlock.getInputTargetBlock('STACK'); | ||
compose: function(this: JoinMutatorBlock, containerBlock: Block) { | ||
let itemBlock = containerBlock.getInputTargetBlock('STACK') as BlockSvg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to say as JoinMutatorItemBlock
here, to avoid the cast below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I do that, I have to cast every time I call getNextBlock
, because it returns BlockSvg
and that may not have a valueConnection_
on it.
I could declare it so that getNextBlock
overrides and returns a JoinItemBlock
but I don't think that's better than treating it as a BlockSvg
overall and a JoinItemBlock
when I need the valueConnection_
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Attempt #N at writing a coherent reply comment here:)
I think casting the result of getNextBlock()
is the correct thing to do in any case (at least pending adding an actual runtime type check in a future PR), but I don't think it matters very much for overall.
*/ | ||
saveConnections: function(containerBlock) { | ||
saveConnections: function(this: JoinMutatorBlock, containerBlock: Block) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again: a more specific type for containerBlock
should be possible and might be useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm neutral on the specific type for the container block. Do you want me to add it? My default is to leave it alone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's not useful at the moment then I agree about leaving it alone.
blocks/text.ts
Outdated
*/ | ||
const TEXT_INDEXOF_TOOLTIP_EXTENSION = function() { | ||
const INDEXOF_TOOLTIP_EXTENSION = function(this: Block) { | ||
// Assign 'this' to a variable for use in the tooltip closure below. | ||
const thisBlock = this; | ||
this.setTooltip(function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not done in previous blocks PRs, but noting the impending PR #7014 enables eslint in theblocks/
directory: might as well use an arrow function here, and avoid the wrath of eslint (and the need for const thisBlock = this
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With one nit (remove Mixin
from a Block
type's name) this LGTM.
blocks/text.ts
Outdated
/** Type of a block that has QUOTE_IMAGE_MIXIN */ | ||
type QuoteImageMixinBlock = Block&QuoteImageMixin; | ||
interface QuoteImageMixin extends QuoteImageMixinType {} | ||
type QuoteImageMixinType = typeof QUOTE_IMAGE_MIXIN; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but can we at least remove "Mixin" from QuoteImageMixinBlock
? Because otherwise (for consistency with the naming convention established everywhere else) the other two should be QuoteImageMixinMixin
and QuiteImageMixinMixinType
.
blocks/text.ts
Outdated
compose: function(containerBlock) { | ||
let itemBlock = containerBlock.getInputTargetBlock('STACK'); | ||
compose: function(this: JoinMutatorBlock, containerBlock: Block) { | ||
let itemBlock = containerBlock.getInputTargetBlock('STACK') as BlockSvg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Attempt #N at writing a coherent reply comment here:)
I think casting the result of getNextBlock()
is the correct thing to do in any case (at least pending adding an actual runtime type check in a future PR), but I don't think it matters very much for overall.
The basics
npm run format
andnpm run lint
The details
Resolves
Part of #6828
Proposed Changes
Behavior Before Change
Behavior After Change
Reason for Changes
Test Coverage
Documentation
Additional Information