-
Notifications
You must be signed in to change notification settings - Fork 36
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
Typescript) fix errors #202
base: main
Are you sure you want to change the base?
Conversation
add some types
#we should remove jasmine..
switch d.ts-version for jasmine (the project used jasmine 1.3)
1) [] => new Array 2) childNodes => children 3) extend some global type-defs
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.
👍 Great changes thank you. Will keep checking back and reviewing!
builds/knockout/src/index.ts
Outdated
options: { | ||
bindingGlobals: defaultOptions.global, | ||
bindingStringPreparsers: [functionRewrite] | ||
} | ||
}) | ||
|
||
// @ts-ignore: Build-Parameter |
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.
also declare const
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.
Done
expect(clickedVM).toEqual(vm()); | ||
|
||
// set the view-model to a new object | ||
vm({ someProp: observableConstructor('My new prop value'), checkVM: checkVM }); | ||
expect(testNode.childNodes[0].childNodes[0].value).toEqual('My new prop value'); | ||
expect(child.value).toEqual('My new prop 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.
To make sure it has the latest DOM structure, child should be a function i.e.
const child = () => testNode.childNodes[0].childNodes[0] as HTMLInputElement
... because part of the assertion here is the DOM structure i.e. testNode.childNodes[0].childNodes[0]
may no longer be child
here, and if that were the case we'd want this test to fail. That failure wouldn't be visible if input
is a reference to the input.
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.
Done
@brianmhunt: The reactivation of CodeQL worked so well that it directly filled all PRs with warnings. For now, I left it at a trigger via cron and deactiviated it on any PR. We would first have to configure a “meaningful” baseline for CodeQL. |
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.
Some more comments, great progress, thank you! I will return for more
@@ -27,7 +27,8 @@ import {bindings as coreBindings} from '@tko/binding.core' | |||
import '@tko/utils/helpers/jasmine-13-helper' | |||
|
|||
describe('Binding: If', function () { | |||
beforeEach(jasmine.prepareTestNode) | |||
var testNode : HTMLElement |
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.
prefer let
to avoid hoisting?
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 would fix this globally with eslint in another PR afterwards. It's already prepared in @Auge19's branch.
@@ -26,7 +26,8 @@ import { | |||
import '@tko/utils/helpers/jasmine-13-helper'; | |||
|
|||
describe('else inside an if binding', function () { | |||
beforeEach(jasmine.prepareTestNode); | |||
var testNode : HTMLElement |
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.
prefer let (not a blocker, just noting)
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.
Done
@@ -281,7 +318,7 @@ export class ForEachBinding extends AsyncBindingHandler { | |||
if (as) { | |||
return v => this._contextExtensions($ctx.extend({ [as]: v })) | |||
} else { | |||
return v => $ctx.createChildContext(v, null, ctx => this._contextExtensions(ctx)) | |||
return v => $ctx.createChildContext(v, undefined, ctx => this._contextExtensions(ctx)) |
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 assume our tests will cover the consequences of this, and that it's fine, but just noting that it's a somewhat semantic change in fairly fickle code. Probably ok, but noting just in case.
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.
It should be covered. I'm always a bit unsure about this situations in JS. Is there a general rule like "undefinied is better than null" in JS/TS-Styling-Guides?
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.
The general rule is that they are different and fickle and all a bit insane e.g.
undefined == null is true // equality with type-cast
undefined === null is false // strictly inequal
null + 1 is 1
undefined + 1 is NaN
function x (def = 1) { return def }
x(null) is null
x(undefined) is 1
typeof null is "object"
typeof undefined is "undefined"
So it's often dangerous to change old code from null
to undefined
and vice versa because of these (and many more) subtle differences that may not be immediately apparent, particularly if they're not covered by tests.
If we can keep this as null
, that'd be safer.
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 looked at the specific location again. The type definition is taken from the official "knockout.d.ts": dataItemAlias?: string
The value is also "safely" handled with if (dataItemAlias)
L116 at bindingContext.ts.
At this point I would call it a type error in foreach.ts. In general, however, I agree with you, we have to validate something like this case-by-case. Unfortunately JS allowed both. If you like, we can leave it at dataItemAlias?: string | null
.
deleted: any[] | ||
} | ||
|
||
interface ChangeAddItem{ |
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.
A stronger type here is:
interface ChangeAddBatchItem {
status: 'added'
index: number
isBatch: true
values?: any[]
}
interface ChangeAddOneItem {
status: 'added'
index: number
isBatch?: false
value: any
}
type ChangeAddItem =
| ChangeAddBatchItem
| ChangeAddOneItem
then one can typeguard on this i.e.
const c: ChangeAddItem = ...
if (c.isBatch) {
// c is ChangeAddBatchItem
c.values
c.value // TypeError
} else {
// c is ChangeAddOneItem
c.value
c.values // TypeError
}
Not strictly needed, but good to have
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.
Done
// Utilities | ||
const MAX_LIST_SIZE = 9007199254740991 | ||
|
||
// from https://github.com/jonschlinkert/is-plain-object | ||
function isPlainObject (o) { | ||
function isPlainObject (o): o is Object { |
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.
The canonical object type is o is Record<string, any>
, since Object
is the parent of Array, Function, and many other classes.
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.
Done
watchForSelectionChangeEvent (element, ieUpdateModel) { | ||
|
||
// All variables are not found! | ||
watchForSelectionChangeEvent (element?) { |
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.
it's unclear what's happening here and it doesn't seem related to the change of types so we might consider a separate PR to make sure the implications are well understood.
Could we break this particular change into a separate PR?
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.
At this point we noticed through the typing that the old IE 8/9 logic could not have worked at all. We made it tsc compliant for now and added a FIXME maker.
I think that we can in a later separate pr, remove all IE8 to IE10-Logic. IE11 could be discussed.
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.
element
can be undefinied , handler
is never defined, ieUpdateModel
will not be handed over
packages/binding.core/src/let.ts
Outdated
export default { | ||
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) { | ||
init: function (element, valueAccessor, allBindings, viewModel, bindingContext: BindingContext) { // allBindings and viewModel not used! |
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.
We could use the convention to start unused vars with _
e.g.
init: function (element, valueAccessor, _allBindings, _viewModel, bindingContext: BindingContext) {
then the comment isn't needed and in many editors the variable will have a different color for the unused var
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.
@M-Kirchhoff has this adapted.
Actually, we should collect such things in a general TKO style guide.
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 up to 55/193 files, making progress. Thank you!
@@ -33,7 +33,8 @@ import '@tko/utils/helpers/jasmine-13-helper'; | |||
describe('Binding dependencies', function () { | |||
var bindingHandlers | |||
|
|||
beforeEach(jasmine.prepareTestNode); | |||
var testNode : HTMLElement |
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.
prefer let
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.
Done, changed in 44 files ;) Let's do the rest later with eslint, it can be automated.
packages/bind/src/bindingContext.ts
Outdated
self.$parent = parentContext.$data | ||
self.$parents = (parentContext.$parents || []).slice(0) | ||
self.$parent = parentContext?.$data | ||
self.$parents = (parentContext?.$parents || []).slice(0) |
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 assume $parents cannot be a falsy e.g. false
or 0
, but to be safe it's generally better to use ...?.$parents ?? []
(not needed, just noting)
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.
Done
@@ -147,30 +196,30 @@ Object.assign(bindingContext.prototype, { | |||
extend (properties) { | |||
// If the parent context references an observable view model, "_subscribable" will always be the | |||
// latest view model object. If not, "_subscribable" isn't set, and we can use the static "$data" value. | |||
return new bindingContext(inheritParentIndicator, this, null, function (self, parentContext) { | |||
return new bindingContext(inheritParentIndicator, this, undefined, function (self, parentContext) { |
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 assuming this has no material difference, but it's semantic and not just a type change, so we want to be mindful of knock-on consequences.
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.
Link to packages/binding.foreach/src/foreach.ts discussion
// We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them) | ||
if (node && (node.nodeType === 1 || node.nodeType === 8)) { | ||
return storedBindingContextForNode(node) | ||
} | ||
} | ||
|
||
export function dataFor (node) { | ||
export function dataFor<T = any>(node: Node): T | undefined { |
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 not clear on what this generic does. Which is ok, and maybe I'll see it when it's used, but just noting.
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.
Comes from the official d.ts files.. Only for the return value relevant. We intended to keep things as similar as possible. In reality, we had to compromise to the current state of implementation.
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 make dts
we can already generate definitions quite well. We would just need a delivery process later.
triggerEvent(testNode.childNodes[0], 'click') | ||
triggerEvent(testNode.children[0], 'click') | ||
triggerEvent(testNode.children[0], 'click') | ||
triggerEvent(testNode.children[0], 'click') |
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 all these .children[0] are ok replacing .childNodes[0]. The only case where there'd be a false positive is if there were two nodes and .childNodes[0] !== .children[0] and clicking on the .children[0] created a false positive. That doesn't seem likely here, so I'm ok with it, just noting.
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.
alright, triggerEvent needs an element
@@ -281,7 +318,7 @@ export class ForEachBinding extends AsyncBindingHandler { | |||
if (as) { | |||
return v => this._contextExtensions($ctx.extend({ [as]: v })) | |||
} else { | |||
return v => $ctx.createChildContext(v, null, ctx => this._contextExtensions(ctx)) | |||
return v => $ctx.createChildContext(v, undefined, ctx => this._contextExtensions(ctx)) |
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.
The general rule is that they are different and fickle and all a bit insane e.g.
undefined == null is true // equality with type-cast
undefined === null is false // strictly inequal
null + 1 is 1
undefined + 1 is NaN
function x (def = 1) { return def }
x(null) is null
x(undefined) is 1
typeof null is "object"
typeof undefined is "undefined"
So it's often dangerous to change old code from null
to undefined
and vice versa because of these (and many more) subtle differences that may not be immediately apparent, particularly if they're not covered by tests.
If we can keep this as null
, that'd be safer.
@@ -33,29 +27,29 @@ describe('Array to DOM node children mapping', function () { | |||
} | |||
setDomNodeChildrenFromArrayMapping(testNode, array, mapping) | |||
expect(testNode.childNodes.length).toEqual(4) |
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.
@brianmhunt This is also a useful methodology to deal with the assertion problem in the ChildNodes/Children adaptation.
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 I'm back to 37/193 files reviewed, so we're actually going in reverse here. :)
Github is not good at these huge PR reviews. Is there any way we could create a series of PRs based on the changes here?
Having looked through a lot, much of it seems safe, but we want to a comprehensive second set of eyes just in case. e.g. can you pick 5-10 files and create a PR for those? I'm open to other strategies, but getting this very-large PR merged all-at-once may be a challenge.
The only general change that I think I'd like to discuss is using new Array()
instead of []
. How strong are you on that / are there alternatives?
Just as a rubber duck I asked Claude AI why one would prefer new Array()
over []
and it somewhat aligned with my own thinking. I might be missing something and am open to discussion, but it was on my mind so wanted to investigate / raise it.

Thank you!
@brianmhunt I think we going in reserve with the review because of doing changes while you reviewing it. The last suggested const-to-let-convertation hits 44 files. I suggest we hold off on further changes to this PR until your review is complete. We are currently very motivated and would like to achieve 100% TSC conformity with this PR so that further improvements to TKO are possible on this basis. Regarding the array topic, it is a tick for now so that the type system works: push, length and co are defined like an Update 1: Update 2: In fact, these are different array variants. The following article examines this. https://medium.com/@julienetienne/different-types-of-arrays-in-javascript-and-when-to-use-them-77f7843b71de Eslint would also find this flaw if a length is not defined: https://eslint.org/docs/latest/rules/no-array-constructor - eslint can partly fix this automatically, but... i would like to leave the topic as it is in this PR and tackle it in a second step together with the ESLINT installation. It generates 156 new warnings, which we would then correct by defining the array in a type-safe manner as number[] or something similar. Can we stay this way? A convert to typeof any[] would be another solution.. |
Ok that should work, as long as this branch stays frozen (and we can do PRs into this branch, but wait to merge them), this should prevent the need to re-review. If there are things to fix in this PR we can decide whether it happens here or in a chained PR.
Thanks for the summary, I see it's the noImplicitAny and strictNullChecks, which are both very useful here. Leaving them in works for me, it'll be easy to find the I'll continue on in the review of this PR. Thanks @phillipc For future reference: |
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 up to 70/193 files reviewed. Thank you!
@@ -26,11 +26,14 @@ import { bindings as templateBindings } from '@tko/binding.template' | |||
import { bindings as ifBindings } from '@tko/binding.if' | |||
|
|||
import '@tko/utils/helpers/jasmine-13-helper' | |||
import { Provider } from '@tko/provider' |
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.
is this used? maybe import type { Provider } ...
?
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.
for (const [key, BindingHandlerClass] of bindingsGenerated) { | ||
// Go through the sorted bindings, calling init and update for each | ||
function reportBindingError (during, errorCaptured) { | ||
const reportBindingError = function (during, errorCaptured) { |
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.
it seems odd to make this anonymous, so it won't report in stack traces. probably ok, though.
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.
IMO such a function should even better be anonymous and const, otherwise there may be problems with the scope. https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
@@ -29,33 +30,38 @@ describe('Binding: Enable/Disable', function () { | |||
var myObservable = observable() | |||
testNode.innerHTML = "<input data-bind='enable:myModelProperty()' />" | |||
applyBindings({ myModelProperty: myObservable }, testNode) | |||
|
|||
expect(testNode.childNodes[0].disabled).toEqual(true) | |||
var input = testNode.children[0] as HTMLInputElement |
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.
should be const
. small thing, but just to prevent hoisting since it's used a bunch in the other functions here where it could impact outcomes
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.
Done in Auge19#4
@@ -40,8 +41,8 @@ describe('Binding: Selected Options', function () { | |||
|
|||
it('Should set selection in the SELECT node to match the model', function () { | |||
var bObject = {} | |||
var values = new observableArray(['A', bObject, 'C']) | |||
var selection = new observableArray([bObject]) | |||
var values = observableArray(['A', bObject, 'C']) |
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.
should be const
(not a blocker here, just noting)
@@ -28,70 +29,76 @@ describe('Binding: CSS style', function () { | |||
}) | |||
|
|||
it('Should be able to use standard CSS style name (rather than JavaScript name)', function () { | |||
var myObservable = new observable('red') | |||
var myObservable = observable('red') |
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.
also let
. I'll just note that generally and we can review/revisit in the future, it's not blocking, just noting.
@@ -183,7 +186,7 @@ describe('Binding: Using', function () { | |||
testNode.innerHTML = "<div data-bind='using: someitem'>text" + | |||
"<!-- ko foreach: childprop --><span data-bind='text: $data'></span><!-- /ko --></div>" | |||
|
|||
var childprop = observableArray([]) | |||
var childprop: ObservableArray = observableArray([]) |
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.
weird that the : ObservableArray
is needed, I'd expect observableArray([])
to provide that
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.
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.
Done, changed to generic in Auge19#4
Thanks @brianmhunt for the current process and progress. I have collect some fruther task here: #211 . I would be very interested in your thoughts on this points. |
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.
👍 77/193
"noEmit": true, | ||
"noEmit": true, //Deactivate "noEmit" to generating d.ts-File to 'builds/dts/dist' via "make dts" | ||
"emitDeclarationOnly": true, | ||
"outDir": "builds/dts/dist", |
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 feel like the builds/dts/dist may change depending on whether it's the knockout or the tko build, but also it's ok for now - just noting.
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.
This is just an poc for now. The normal build chain is not affected by these parameters. I'm still unclear on how best to build a typing package. Once the PR is complete, I'd like to try it with https://www.npmjs.com/package/esbuild-plugin-d.ts
Regarding the build pipeline, I would preferred something like a one file bundle for TKO and @types/tko, with an esm export: export var tko
. Corresponds to browser.es6.js
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.
Thanks, I'm not clear on the best build strategy either. It'd be nice if the only dependency were Typescript itself, for the typing.
On the @types/tko we should be ok, noting that the static global for the knockout and the tko build may be different, so we want to be mindful of that.
"noEmit": true, //Deactivate "noEmit" to generating d.ts-File to 'builds/dts/dist' via "make dts" | ||
"emitDeclarationOnly": true, | ||
"outDir": "builds/dts/dist", | ||
/*Disable some typing feature from ts to detect first steps to a strong typed version*/ |
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.
👍
return JSON.parse(jsonString) as T; | ||
} | ||
// Fallback on less safe parsing for older browsers | ||
return (new Function('return ' + jsonString))() as T |
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.
Noting (aside) we should really rely on JSON as a polyfill, if it's not defined.
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.
This new Function(string)
is like evil eval.
Good point, probably this case is generally obsolete. I think it is for IE < 8 and old Safari browser.. https://caniuse.com/json
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.
yeah I think it's safe/wise to pull this out. It opens a vector to arbitrary code execution - if someone can unset the global JSON the fallback is dangerous. We're relying on newer things than JSON, so this won't be the thing that breaks TKO.
set: function (name, value) { | ||
options[name] = value | ||
}, | ||
onError (e : Error) : void { throw e } |
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.
stylistically, the x:type
is preferable to x : type
, the latter looking a bit too much like a ternary. (not a blocker, just noting)
|
||
// jQuery will be automatically set to globalThis.jQuery in applyBindings | ||
// if it is (strictly equal to) undefined. Set it to false or null to | ||
// disable automatically setting jQuery. | ||
jQuery: globalThis.jQuery, | ||
jQuery : JQueryStatic | boolean | null = (globalThis as any).jQuery |
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 not sure it can ever be true, just false
jQuery : JQueryStatic | false | null = (globalThis as any).jQuery
Nothing needed to change here, just noting
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.
Fixed in Auge19#4
// | ||
// This becomes ko.options | ||
// -- | ||
// | ||
// This is the root 'options', which must be extended by others. | ||
export class Options { | ||
[key: string]: any; |
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.
do we want this? doesn't that make all the other types any
?
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.
The declared ones win's, but I would preferred to remove the index access here. We have some hidden options in the codebase. Declaring those is the better way.
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.
Fixed in Auge19#4
import { Provider } from "@tko/provider"; | ||
|
||
interface CustomBindingGlobalProperties { | ||
String; |
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.
unclear what String
is
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.
It was wrong, fixed it Auge19#4
interface CustomBindingGlobalProperties {
[customBindingName: string]: any;
}
String
and isObservable
are only used as test-case-props in templatingBehaviors.ts
export function clonePlainObjectDeep (obj, seen) { | ||
if (!seen) { seen = [] } | ||
export function clonePlainObjectDeep (obj, seen?: any[]) { | ||
if (!seen) { seen = new Array() } |
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.
aside: we could/should improve the perf. here with a Set instead of array for seen
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 took a look at the method and it looks like it's not used anymore. Mark as deprecated?
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.
Yes, even just /** @deprecated */
(in a subsequent PR) would be nice here. It's possible someone is using it externally but it's not a core deliverable of TKO/knockout and trivial to do on your own so I think it'd be good to get rid of it if it's not being used internally.
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.
Done
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.
👍 115/193
@@ -174,21 +177,21 @@ describe('Templating', function () { | |||
setTemplateEngine(new dummyTemplateEngine({ someTemplate: 'template output' })) | |||
testNode.innerHTML = "<div data-bind='template:\"someTemplate\"'></div>" | |||
applyBindings(null, testNode) | |||
expect(testNode.childNodes[0].innerHTML).toEqual('template output') | |||
expect((testNode.childNodes[0]as HTMLElement).innerHTML).toEqual('template output') |
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.
small thing: whitespace before as
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.
oh, fixed in Auge19#4
|
||
elseChainSatisfied((unwrap(dataArray) || []).length !== 0) | ||
elseChainSatisfied((unwrap(dataArray) || []).length !== 0); |
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.
it'd be nice if the style guide here highlighted and ideally removed unnecessary semicolons
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've already prepared prettier here. It's configured to maintain the existing style: https://github.com/Auge19/tko/tree/add_prettier
Personally, I would prefer globaly ending semicolons.
@@ -171,7 +179,7 @@ export function renderTemplate (template, dataOrBindingContext, options, targetN | |||
// Ensure we've got a proper binding context to work with | |||
var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof BindingContextConstructor)) | |||
? dataOrBindingContext | |||
: new BindingContextConstructor(dataOrBindingContext, null, null, null, { 'exportDependencies': true }) | |||
: new BindingContextConstructor(dataOrBindingContext, undefined, undefined, undefined, { 'exportDependencies': true }) |
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.
possibly semantically relevant i.e. undefined !== null. Likely ok, but noting.
@@ -56,7 +56,7 @@ describe('Throttled observables', function () { | |||
// Wait until after timeout | |||
waitsFor(function () { | |||
return notifiedValues.length > 0 | |||
}, 300) | |||
}, "Timeout", 300) |
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.
it would be stronger to declare const waitsFor: (...) => ...
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.
waitsFor
from Jasmine 1.3 is only declared with this three parameters:
declare function waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void;
Adding a creative failure messages like "Timeout" is compliant with the jasmine typings, although this magic always happens:
jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
var latchFunction_ = null;
var optional_timeoutMessage_ = null;
var optional_timeout_ = null;
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
switch (typeof arg) {
case 'function':
latchFunction_ = arg;
break;
case 'string':
optional_timeoutMessage_ = arg;
break;
case 'number':
optional_timeout_ = arg;
break;
}
}
var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
this.addToQueue(waitsForFunc);
return this;
};
expect(function () { | ||
observable.extend({deferred: false}) | ||
observable.extend(Object.assign({deferred: false})) |
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.
This is a no-op. i.e. Object.assign
isn't doing anything here. It's harmless, but worth removing (either in this PR or the next)
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.
Done, Auge19#4
// Convert value to uppercase | ||
filters.uppercase = function (value) { | ||
return sproto.toUpperCase.call(unwrap(value)) | ||
interface Filters { |
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.
many consumers of Knockout/TKO will extend the filters, so this type has to be exposed for others to extend it.
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.
export is added, see Auge19#4
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.
This looks to mostly be re-organizing, and I didn't spot any semantic changes but it was a lot of changes so I may have missed something. Please let me know if there were any semantic changes here, but otherwise it's all good.
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 have check this, too. Only the implementation style is changed.
} from '../dist' | ||
} from '../src' | ||
|
||
import { assert } from 'chai'; |
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.
import order should have relative imports after vendor/absolute i.e. 'chai' before '../src'
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.
Changed in Auge19#4 . It is only a stylistic pattern or is there another reason?
@@ -48,11 +50,12 @@ describe('KO LifeCycle', function () { | |||
assert.isFunction(Child.prototype.anchorTo) | |||
assert.isFunction(Child.prototype.dispose) | |||
assert.isFunction(Child.prototype.addDisposable) | |||
assert.isNotFunction(Child.prototype.mixInto) | |||
// TODO: Fails with tsc, check if test is obsolte with typescript | |||
// assert.isNotFunction(Child.prototype.mixInto) |
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.
Noted. Since it's unlikely to be used and a strange/rare pattern, this feels ok to me.
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.
Alternatively we could use any or set ts-ignore for the isNotFunction
check?
|
||
// For arrays, also respect toJSON property for custom mappings (fixes #278) | ||
if (typeof rootObject['toJSON'] === 'function') { visitorCallback('toJSON') } | ||
if (typeof rootObject['toJSON'] === 'function') { visitorCallback('toJSON') } |
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.
wrong indent?
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.
Fixed in Auge19#4
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.
up to 175/193 . Thanks for all the hard work here.
I've added a few comments, some are meaningful, but nothing strictly blocking.
The remaining files tend to be larger ones, so may take a bit each, but will turn to it as soon as I can. Thank you!
if (node.tagName === 'SLOT') { | ||
const parent = node.parentNode | ||
const slotName = node.getAttribute('name') || '' | ||
const openNode = document.createComment(`ko slot: "${slotName}"`) | ||
const closeNode = document.createComment('/ko') | ||
|
||
if(!parent) |
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.
should use if (...) { ... }
by convention / clarity / lint
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 a blocker, but noting)
@@ -38,6 +38,9 @@ import { | |||
|
|||
import * as coreBindings from '@tko/binding.core'; | |||
|
|||
import { assert} from "chai" |
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.
these vendor imports should be above the "relative" imports (not a blocker)
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.
Done in Auge19#4, i have also fixed unneeded imports and testseries closure. I think everything is only stylistic icing on the cake.
@@ -3,6 +3,8 @@ import { | |||
MultiProvider | |||
} from '../dist' | |||
|
|||
import { assert } from "chai" |
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.
should be before relative imports
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.
Done, Auge19#4
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.
unclear in review whether it's ok to delete this, just noting. I imagine if the tests still run it's fine, but noting.
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 have merge this file with the central file: utils/helpers/jasmine-13-helper.ts
. All globally declared custom matchers should be always available.
@@ -251,7 +251,7 @@ describe('Interpolation Markup bindings', function () { | |||
|
|||
jasmine.setNodeText(testNode, "hello {{'name'}}!"); | |||
applyBindings(null, testNode); | |||
expect(testNode).toContainText('hello --name--!'); | |||
expect(testNode).toContainText('hello --name--!'); */ |
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.
are we removing a test expect here? do we lose some coverage?
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.
This test-case was already deactivited via xit
, so we saved ourselves the type correction.
} from '@tko/utils' | ||
import { subscribable, dependencyDetection } from '@tko/observable' | ||
import { getObjectOwnProperty, tasks } from '@tko/utils' | ||
import { Loader } from './loaders' |
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.
import type
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.
Done, see Auge19#4
// For testing purposes, we make this synchronous. | ||
detachAndDispose (node) { | ||
super.detachAndDispose(node) | ||
cleanNode(node) | ||
} | ||
|
||
dispose () { |
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.
this is a no-op
@@ -1,6 +1,8 @@ | |||
|
|||
import { memoization } from '../dist' | |||
|
|||
//import { } from "karma-jasmine"; |
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.
unneeded
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.
Done, see Auge19#4
@@ -52,7 +53,9 @@ export function unmemoizeDomNodeAndDescendants (domNode, extraCallbackParamsArra | |||
} | |||
} | |||
|
|||
export function parseMemoText (memoText) { | |||
export function parseMemoText (memoText : string | null) : string | null { | |||
if(!memoText) |
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.
needs if () { ... }
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.
Done, see Auge19#4
As announced, we have started to make TKO more type-safe. To get a startpoint, we have set the tsconfig as softly as possible and continue to allow "any" types.
We (@Auge19 , @mcselle ) validate the typescript code with tsc. The current status is only 313 errors left. We began with 7410 errors. With this draft PR we would like to get feedback and start our own review. The goal is 0 errors with tsc. If this PR is ready and merged, we would like to continue with ESLINT.
All tests continue to pass.