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

Improve TS Support #239

Merged
merged 10 commits into from
Sep 18, 2017
Merged

Improve TS Support #239

merged 10 commits into from
Sep 18, 2017

Conversation

sgtoj
Copy link
Contributor

@sgtoj sgtoj commented May 4, 2017

See #238 for more information.

@sgtoj sgtoj mentioned this pull request May 4, 2017
6 tasks
@duluca
Copy link
Contributor

duluca commented May 5, 2017

@sgtoj I've started the review, this may be more productive if I sent you a PR to fix some of the grammar stuff, which will also give me a chance run the code and look at how things are fitting together. I'm getting ready for a conference talk for tomorrow. So expect to hear from me again sometime Saturday!

@sgtoj sgtoj changed the title Improved TS Support Improve TS Support May 5, 2017
@duluca
Copy link
Contributor

duluca commented May 8, 2017

@sgtoj @searls not sure if my testing methodology is correct here, but i'm running into an error. I tried to execute test/src/typescript/test.ts using node after running tsc on it to transpile it to a .js file.

Here's the error message that gets thrown when const bear = td.object<Dog>("Bear"); executes


:43:4)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)

I then attempted to dig into the object<T> declaration and lost the trail with export type DoubledObject<Subject> = Subject; I'm unable to find where Subject is defined.

I'm still getting oriented with the code base. Some help and direction would be appreciated.

@sgtoj
Copy link
Contributor Author

sgtoj commented May 10, 2017

@duluca Subject is defined as the generic parameter. So...

(DoubledObject<Subject> = Subject) === (DoubledObject<T> = T)

@sgtoj
Copy link
Contributor Author

sgtoj commented May 10, 2017

@duluca I would prefer to use T, though.

@duluca
Copy link
Contributor

duluca commented May 12, 2017

@sgtoj Ah I see, naming generics other than T is usually then when you limit what types can be used by the generic. If you can use any object, T or TObject makes sense. If say, the object must implement an interface called IDocument, then calling it TDocument helps the user understand what's expected. So here I'd recommend going with T or TSubject. However having an ISubject defined would be helpful, if you expect the object to have specific shape. But I also don't get what DoubledObject<T> = T accomplishes :)

@duluca
Copy link
Contributor

duluca commented May 12, 2017

@sgtoj So here export type DoubledObjectWithKey<T extends string> = { [K in T] }; it is fair, and actually quite helpful to call it TString.

@sgtoj
Copy link
Contributor Author

sgtoj commented May 12, 2017

DoubledObject<T> = T was DoubledObject<Subject> = Subject before I changed it to be consistent with the rest of the definition. I am not sure what the original author's motivation behind the naming of the types defined at the top.

Although I normally see single-letter -- T, K, V, etc -- type parameter names, I am open to the idea of using TObject, etc.

I just looked where the letters originated. Apparently, this convention is adopted from Java and C#.

@searls
Copy link
Member

searls commented May 12, 2017

I'm not a Typescript user, but I agree that generic types should use single-letter placeholders like T and K,V as those are overwhelmingly common conventions and point out to users that they are customizable.

The real tricky bit that I would want to accomplish from a type awareness for td.js is for any created test double to have its type inferred or specified such that a compilation failure is triggered until the type is created. Same goes with creating a stubbing which then fails compilation and requires the method be written.

To express this with code, what I want is for it to support a workflow like I would have in Java + Mockito. Here's how that would normally flow

public void testInvoices() {
  // 1. Write the fake you want
  LoadsPayments loadsPayments = mock(LoadsPayments.class) 
  // 2. get compiler feedback that you need to go define LoadsPayments (e.g. hit ctrl-1 to quick-fix create the type

  // 3. Write a stubbing of the method you want the fake to define
  Payment payment = new Payment()
  when(loadsPayments.load(new Date())).thenReturn([payment])
  // 4. get compiler feedback that `LoadsPayments` needs an instance method `load` with parameters `(Date)`  and return type `Array<Payment>`, prompting me to go create that in a way that my tools can auto-generate for me

  // … rest of test goes here



}

This sort of paint-by-numbers approach where writing a single isolated test informs the tooling with what it needs to create all the files/classes for you is a fantastic productivity win, and one that encourages lots of small custom types.

How possible is this going to be with TypeScript?

@duluca
Copy link
Contributor

duluca commented May 12, 2017

Yeah I saw, that was a great change. And I have more C# experience than I care to admit. Given the same guy invented C# and TypeScript, I think it's fair to carry over the conventions. And naming generics start with a capital T (i.e. TSubject or TString) is similar to how you name interfaces with a capital I (i.e. ISubject).

K and V are stand-ins for Key and Value. Personally I prefer TKey and TValue.

@duluca
Copy link
Contributor

duluca commented May 12, 2017

@searls I know that we can do that easily if we rewrite portions of the app in TypeScript, not sure if it can be achieved through type definitions alone. But then the library can be compiled down to JavaScript and continue to used without any notion of TypeScript by consumers, if they choose to.

Or we could write a wrapper.

@searls
Copy link
Member

searls commented May 12, 2017 via email

@sgtoj
Copy link
Contributor Author

sgtoj commented May 12, 2017

I am also interested on that project too. May do some work towards it weekend.

@duluca
Copy link
Contributor

duluca commented May 12, 2017

@sgtoj @searls I've noticed that yarn test:typescript merely transpiles the file, doesn't attempt to run it. Thus not an adequate test harness.
So,

  1. We need to implement test script, which will execute the code
  2. Fix the test code so ln 58: td.replace({}, "prop"); doesn't error out
  3. Only then can this PR be considered as verified by the CI process

@sgtoj let me know if you need help

Copy link
Contributor

@duluca duluca left a comment

Choose a reason for hiding this comment

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

We need to implement test script, which will execute the code
Fix the test code so ln 58: td.replace({}, "prop"); doesn't error out

index.d.ts Outdated
@@ -94,6 +100,16 @@ export function explain<T>(f: TestDouble<T>): Explanation;
// fake: constructors
// ----------------------------------------------------------------------------

/**
* Create a fake object constructor the given class.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think for is missing before the given class

export function object<T>(object: string): DoubledObject<T>;

/**
* Create a fake object that is deep copy of the given object.
Copy link
Contributor

Choose a reason for hiding this comment

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

a deep copy

@sgtoj
Copy link
Contributor Author

sgtoj commented May 26, 2017

@duluca Sorry... I will review and fix tonight or this weekend. So far, I have already these TS definitions for 2 different work projects; with 2 more in the works. I haven't found any issues yet.

@duluca
Copy link
Contributor

duluca commented May 26, 2017

In package.json the property "test:typescript" should look like:
"tsc -p ./test/src/typescript && node ./test/src/typescript/test.js && rm ./test/src/typescript/test.js".
This ensure test.js is generated, executed using Node and clean up the file after a successful run. Currently this fails due to the error I had initially reported.

@duluca
Copy link
Contributor

duluca commented Jun 14, 2017

@sgtoj I fixed up test.ts in #260, also updated package.json to actually execute the code. So once the PR can be merged, it'd be great to update this PR from master, so there's a valid CI run against this change.

TODO:
[ ] Update from master once #260 is merged
[ ] Update this PR and make sure CI checks pass

@searls
Copy link
Member

searls commented Jun 18, 2017

Ping that #260 is merged -- should this be revisited?

@duluca
Copy link
Contributor

duluca commented Jun 19, 2017

@sgtoj do you need help with this?

@sgtoj
Copy link
Contributor Author

sgtoj commented Sep 15, 2017

I have merged from upstream master, fixed one conflict, and fixed one problem pointed out by the test.

Copy link
Contributor

@duluca duluca left a comment

Choose a reason for hiding this comment

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

test.ts was intentionally moved under the regression folder

  1. Keeps it out of the src folder to prevent accidental distribution
  2. The CI server compiles and executes the ts code in JavaScript to ensure correct functionality

By moving code from regression to src, you're by-passing CI. Thus making this an invalid PR. Please move test code back in to the regression file.

@sgtoj
Copy link
Contributor Author

sgtoj commented Sep 15, 2017

That makes sense. I was very confused too. I will fix.

@searls
Copy link
Member

searls commented Sep 16, 2017

@duluca please advise if you would like to merge and what version segment is appropriate to bump

@duluca
Copy link
Contributor

duluca commented Sep 16, 2017

@searls It makes sense to me as a patch increment.

@searls searls merged commit 5a11a57 into testdouble:master Sep 18, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants